0%

简介

  • Flutter是谷歌的移动UI框架,可以快速开发出高质量的原生用户界面,并且Flutter是完全免费开源的.现在Flutter至少可以跨5种平台,如:MacOS,Windows,Linux,Android,iOS,甚至还可以在谷哥的Fuchsia系统上运行.

开始

  • 当然,最新,最权威的技术资源还是它的官网文档.这里大部分都按照官网文档的步骤来进行的.

安装Flutter

  • 我这里使用的是Debian系统,而且选择使用它的GitHub的源来安装,而不是下载安一个固定版本的Flutter.
1
2
3
4
5
6
7
8
9
10
11
~$ git clone https://github.com/flutter/flutter.git

~$ export PATH=$PATH:`pwd`/flutter/bin

# 可选的,预先下载一些开发文件.
~$ flutter precache

~$ flutter doctor
~$ which flutter dart
/fullpath/flutter/bin/flutter
/fullpath/flutter/bin/dart

编辑器支持

Android Studio and IntelliJ,VS Code, Emacs

  • Android Studio 至少需要3.6.3以上的片本.AS与VS需要安装上Flutter pluginDart plugin插件扩展.Emacs需要安装lsp-dart package.

国内镜像源

1
2
3
4
5
~$ export PUB_HOSTED_URL=https://pub.flutter-io.cn
~$ export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
~$ git clone -b dev https://github.com/flutter/flutter.git
~$ export PATH="$PWD/flutter/bin:$PATH"
~$ cd ./flutter

更新Flutter

  • 更新Flutter SDK
1
~$ flutter upgrade
  • Flutter有4种发布版本:stable,beta,dev,master,一般推存使用stable版本.
1
2
3
~$ flutter channel  # 查看
~$ flutter channel dev
~$ flutter upgrade
  • 更新包资源,类似大多WEB开发一样的, 如修改了工程内的pubspec.yaml后,可以通过更新来解决依赖.
1
~$ flutter pub upgrade
1
~$ flutter pub u
  • 选择特定版本
1
~$ flutter version v1.21.0+hotfix.3

运行flutter doctor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 接授licenses.
~$ flutter doctor --android-licenses
~$ flutter doctor -v
[✓] Flutter (Channel master, 1.21.0-6.0.pre.227, on Linux, locale en_US.UTF-8)
• Flutter version 1.21.0-6.0.pre.227 at /home/michael/3TB-DISK/github/flutter
• Framework revision e9117c1902 (12 hours ago), 2020-08-06 08:15:25 -0700
• Engine revision 36db6cfdd1
• Dart version 2.10.0 (build 2.10.0-3.0.dev 14a6aac97b)


[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
• Android SDK at /home/michael/3TB-DISK/Android/Sdk/
• Platform android-30, build-tools 30.0.1
• ANDROID_HOME = /home/michael/3TB-DISK/Android/Sdk/
• ANDROID_SDK_ROOT = /home/michael/3TB-DISK/Android/Sdk/
• Java binary at: /home/michael/IDE_DIR/android-studio/jre/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
• All Android licenses accepted.

[✓] Linux toolchain - develop for Linux desktop
• clang version 7.0.1-8 (tags/RELEASE_701/final)
• cmake version 3.13.4
• ninja version 1.8.2
• pkg-config version 0.29


[✓] Android Studio (version 4.0)
• Android Studio at /home/michael/IDE_DIR/android-studio
• Flutter plugin version 48.0.2
• Dart plugin version 193.7361
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.47.3)
• VS Code at /usr/share/code
• Flutter extension version 3.13.2

[!] Proxy Configuration
• HTTP_PROXY is set
! NO_PROXY is not set

[✓] Connected device (1 available)
• Linux (desktop) • linux • linux-x64 • Linux
! Doctor found issues in 1 categories.

创建第一个程序

1
2
3
~$ flutter create myapp
~$ cd myapp
~$ flutter run -d linux

Web开发

  • 如果想用Flutter开发Web应用也是可以的,现在只是早期支持,需要切换到beta版本.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ~$ flutter channel beta
    ~$ flutter upgrade

    ~$ flutter config --enable-web
    Setting "enable-web" value to "true".

    You may need to restart any open editors for them to read new settings.
    ~$ cat ~/.flutter_settings
    {
    "enable-linux-desktop": true,
    "enable-windows-desktop": true,
    "enable-web": true
    }

    ~$ flutter devices
    3 connected devices:

    Linux (desktop) • linux • linux-x64 • Linux
    Web Server (web) • web-server • web-javascript • Flutter Tools
    Chrome (web) • chrome • web-javascript • Google Chrome 71.0.3578.98

创建新工程

1
2
3
~$ flutter create myapp
~$ cd myapp
~$ flutter run -d chrome
  • 如果上面运行出错,提示如:Unable to connect to Chrome debug port: 16799,检查是否在环境变量里设置了HTTP_PROXY,unset后再运行.

对已有的应用添加Web支持

1
~$ flutter create .

编译工程

1
~$ flutter build web

Android开发

  • 如上面运行flutter doctor所示,在Android Studio里安装好Dart PluginFlutter plugin. 这里在IDE新建一个Flutter Application工程.

桌面开发

谢谢支持

  • 微信二维码:

硬件简介

硬件架构

  • CC2640R2F器件是一款无线微控制器(MCU),主要适用于Bluetooth® 4.2Bluetooth 5低功耗 应用.cc2640r2f数据手册.
    cc2640r2f_arch_block-diagram.jpeg
  • 下面笔记是参照simplelink_cc2640r2_sdk_1_50_00_58/docs/blestack/ble_user_guide文档,验证总结的.建议有问题查看官方SDK各种文档.

BLE软件架构

  • CC2640R2F蓝牙软件环境包含两个部分:APP应用程序,蓝牙协议栈.应用程序中包含TI RTOS内核,驱动,蓝牙Profie三部.它们两部分之间消息通信是通过ICall来实现.
  • 蓝牙栈的SDK中有是exe的安装包,如果是Linux系统需要从exe里复制出来使用,也可以使用WineHQ来安装本用户目录下.
    cc2640r2f_app_icall_stack.jpeg

开箱测试

蓝牙主机测试(Host_test)

  • Academy教程是在simplelink_academy_cc2640r2sdk_3_40_02_00/modules/projects/ble_hosttest/information.html

导入工程

  • 从本地simplelink_cc2640r2_sdk_3_40_00_10SDK里的examples导入工程examples/rtos/CC2640R2_LAUNCHXL/blestack/host_test/tirtos/host_test_cc2640r2lp_app,导入成功后.
  • 会看到两个工程host_test_cc2640r2lp_apphost_test_cc2640r2lp_stack_library,这个_app工程是要依赖_stack_library工程,所以只编译与Debug这个_app工程时,它会先去调动编译_stack_library工程,该工程会生成一个库文件_stack_library/FlashROM_Library/host_test_cc2640r2lp_stack_library.lib去给到_app工程链接的,这里不像是之前的版本把stack编译成独立的hexbin文件,而是做为一个库去给app链接调用.

编译工程

  • 编译工程,如果想知道IDE在编译工程时的细节,可以这样操作,把Window-->Preferences-->Build-->Console verbosity level选择Verbose.
  • 下面是_app工程的编译与链接以及最终生成hex文件的细节.注意${SDK_DIR}${CCS_DIR},${WORKSPACE}是替换过的实际绝对路径的变量.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[...]
Finished building: "${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/blestack/icall/app/icall_hci_tl.c"

Building target: "host_test_cc2640r2lp_app.out"
Invoking: ARM Linker
"${CCS_DIR}/ccs/tools/compiler/ti-cgt-arm_18.12.3.LTS/bin/armcl"
--cmd_file="${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/blestack/config/build_components.opt"
--cmd_file="${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/blestack/config/factory_config.opt"
--cmd_file="${WORKSPACE}/host_test_cc2640r2lp_stack_library/TOOLS/build_config.opt"
-mv7M3 --code_state=16 -me -O4 --opt_for_speed=0 --define=DeviceFamily_CC26X0R2
--define=Display_DISABLE_ALL --define=CC2640R2_LAUNCHXL --define=CC26XX --define=CC26XX_R2 --define=ICALL_EVENTS
--define=ICALL_JT --define=ICALL_LITE --define=ICALL_MAX_NUM_ENTITIES=6 --define=ICALL_MAX_NUM_TASKS=3
--define=ICALL_STACK0_ADDR --define=MAX_NUM_BLE_CONNS=1 --define=MAX_PDU_SIZE=255 --define=NPI_USE_UART --define=xNPI_USE_SPI
--define=NPI_SPI_CONFIG=Board_SPI0 --define=xPOWER_SAVING --define=STACK_LIBRARY --define=USE_ICALL --define=xdc_runtime_Assert_DISABLE_ALL --define=xdc_runtime_Log_DISABLE_ALL -g --c99 --gcc --diag_warning=225 --diag_wrap=off
--display_error_number --gen_func_subsections=on --abi=eabi -z -m"host_test_cc2640r2lp_app.map" --heap_size=0 --stack_size=256
-i"${CCS_DIR}/ccs/tools/compiler/ti-cgt-arm_18.12.3.LTS/lib" -i"${CCS_DIR}/ccs/tools/compiler/ti-cgt-arm_18.12.3.LTS/include"
--reread_libs --define=CC26X0ROM=2 --diag_suppress=16002-D --diag_suppress=10247-D --diag_suppress=10325-D --diag_suppress=10229-D
--diag_suppress=16032-D --diag_wrap=off --display_error_number --warn_sections
--xml_link_info="host_test_cc2640r2lp_app_linkInfo.xml"
--rom_model -o "host_test_cc2640r2lp_app.out" "./Application/host_test_app.obj" "./Application/util.obj" "./Drivers/ECC/ECCROMCC26XX.obj" "./Drivers/RF/RFCC26XX_singleMode.obj" "./Drivers/TRNG/TRNGCC26XX.obj" "./ICall/icall.obj" "./ICall/icall_cc2650.obj" "./ICall/icall_user_config.obj" "./ICallBLE/ble_user_config.obj" "./ICallBLE/icall_api_lite.obj" "./ICallBLE/icall_hci_tl.obj"
"./NPI/Transport/SPI/npi_tl_spi.obj" "./NPI/Transport/UART/npi_tl_uart.obj" "./NPI/Transport/npi_tl.obj" "./NPI/npi_frame_hci.obj" "./NPI/npi_rxbuf.obj" "./NPI/npi_task.obj" "./PROFILES/devinfoservice.obj" "./PROFILES/gatt_uuid.obj" "./PROFILES/gattservapp_util.obj" "./PROFILES/peripheral.obj" "./PROFILES/simple_gatt_profile.obj" "./Startup/board.obj" "./Startup/ccfg_app_ble.obj" "./Startup/main.obj"
-l"configPkg/linker.cmd" -l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/devices/cc26x0r2/driverlib/bin/ccs/driverlib.lib"
-l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/kernel/tirtos/packages/ti/dpl/lib/dpl_cc26x0r2.aem3"
-l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/drivers/lib/drivers_cc26x0r2.aem3"
-l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/display/lib/display.aem3"
-l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/grlib/lib/ccs/m3/grlib.a"
-l"${WORKSPACE}/host_test_cc2640r2lp_stack_library/FlashROM_Library/ble_r2.symbols"
-l"${WORKSPACE}/host_test_cc2640r2lp_stack_library/FlashROM_Library/lib_linker.cmd"
-l"${WORKSPACE}/host_test_cc2640r2lp_stack_library/FlashROM_Library/host_test_cc2640r2lp_stack_library.lib"
-l"${SDK_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/source/ti/blestack/common/cc26xx/ccs/cc26xx_app.cmd" -llibc.a
<Linking>
Finished building target: "host_test_cc2640r2lp_app.out"

${CCS_DIR}/ccs/tools/compiler/ti-cgt-arm_18.12.3.LTS/bin/armhex -order MS --memwidth=8 --romwidth=8 --intel
-o host_test_cc2640r2lp_app.hex host_test_cc2640r2lp_app.out
Translating to Intel format...
"host_test_cc2640r2lp_app.out" .resetVecs ==> .resetVecs
[...]
  • 连接TI-CC2640R2-LaunchPad板子,查看板子上的XDS110串号.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ~$ ti/ccs920/ccs/ccs_base/common/uscif/xds110/xdsdfu -e

    USB Device Firmware Upgrade Utility
    Copyright (c) 2008-2019 Texas Instruments Incorporated. All rights reserved.
    Scanning USB buses for supported XDS110 devices...
    <<<< Device 0 >>>>

    VID: 0x0451 PID: 0xbef3
    Device Name: XDS110 Embed with CMSIS-DAP
    Version: 3.0.0.11
    Manufacturer: Texas Instruments
    Serial Num: L50012VN
    Mode: Runtime
    Configuration: Standard

    Found 1 device.
  • 修改host_test_cc2640r2lp_app工程文件的targetConfigs/CC2640R2F.ccxml,打开后会显示Basic界面如下图:
    cc2640_debugger_connection
    cc2640_debugger_connection_serial
  • 把串号L50012VN写入上图的Enter the serial number栏中,并保存.现在可以调试或加载host_test_cc2640r2lp_app工程到TI-CC2640R2-LaunchPad板子.

BTool测试

  • BTool是一个PC工具,可以单独下载,SimpleLink SDK里带有最新版本,它在${SIMPLELINK_CORE_SDK_INSTALL_DIR}/simplelink_cc2640r2_sdk_1_50_00_58/tools/blestack/btool.

  • 它的使用说明在${SIMPLELINK_CORE_SDK_INSTALL_DIR}/simplelink_cc2640r2_sdk_3_40_00_10/docs/ble5stack/btool_user_guide/BTool_Users_Guide/index.html.

  • 在Linux下使用btool.exe需要安装mono支持.

    1
    2
    3
    ~$ sudo apt-get install mono -y
    ~$ cd simplelink_cc2640r2_sdk_1_50_00_58/tools/blestack/
    ~$ mono btool.exe
  • Serial Bootloader (SBL)串口启动,Over-the-Air Download(OAD)空中下载.

Bootloader

  • 参照官方文档《CC13x0, CC26x0 SimpleLinkTM Wireless MCU Technical Reference Manual.pdf》第8章描述,swcu117h.pdf,ROM bootlaoder主要功能是为了下载固件的,也可以通过它读取固件.安全起见可以关闭Bootloader功能,也可以设置”后门(8.1.2 Bootloader Backdoor)”.与bootloader的通信接口可以是2-pin UARTSSI.

反向工程

dump ROM

  • 删除flash内存
1
2
3
4
5
6
7
8
9
10
11
12
13
 ti/uniflash_7.1.0$ ./dslite.sh --mode cc13xx-cc26xx-mass-erase -d XDS110
Executing the following command:
> /fullpath/ti/uniflash_7.1.0/deskdb/content/TICloudAgent/linux/ccs_base/DebugServer/bin/DSLite cc13xx-cc26xx-mass-erase -d XDS110

For more details and examples, please refer to the UniFlash Quick Start guide.

Cortex_M3_0: GEL Output: Memory Map Initialization Complete.
Performing Device Unlock via Mass Erase...
Cortex_M3_0: MassErase(): Initializing.
Cortex_M3_0: MassErase(): Issuing Board Reset.
Cortex_M3_0: MassErase(): Mass erase complete.
Device Unlocked

安装GHIDRA

1
2
3
~$ export JAVA_HOME=~/IDE_DIR/jdk-11.0.14.1+1/
~$ export PATH=$JAVA_HOME/bin:$PATH
~$ sdk install gradle 7.4.1
1
2
3
~$ git clone https://github.com/NationalSecurityAgency/ghidra.git
~$ cd ghidra
~$ gradle -I gradle/support/fetchDependencies.gradle init

安装SVD插件

  • 克隆https://github.com/leveldown-security/SVD-Loader-Ghidra$USER_HOME/ghidra_scripts目录下。或者放到安装目录的$GHIDRA_HOME/Ghidra/Features目录下都可以。或者打开Windows-> Script Manager -> Manage Script directories的菜单项,靠近右上角关闭按钮的位置。打开脚本扫描路径的列表,添加一个目录路径,选择SVD-Loader-Ghidra所在位置,再刷新所有的脚本列表. 就会在左边栏里,多了一行leveldown security的目录。

设备配置

厂家配置 Factory Configuration(FCFG)

用户配置 Customer Configuration(CCFG)

  • CCFG片区是在FLASH的尾部(0x1fff=128*1024)它是用来设置硬件功能的,而且是与驱动程序版本是相关联的,CCFG的修改必需与相应驱动程序一致.具体详情可以查看SDK里的示例工程源码.
  • 如:simplelink_cc2640r2_sdk_3_40_00_10/examples/rtos/CC2640R2_LAUNCHXL/ble5stack/host_test/src/ccfg_app_blc.c.它是包含一个设备启动文件simplelink_cc2640r2_sdk_3_40_00_10/source/ti/devices/cc26x0r2/startup_files/ccfg.c.
  • 看文件内的描述,是通过宏把这些定义位(bit)值拼接成字节,再附加到FLASH的尾端,官方建议如果要修改参数,肯定是不要去改动原SDK内的文件,可以自定义一个文件如<customer_ccfg.c>:覆盖原来的参数值如:
1
2
3
4
#define SET_CCFG_BL_CONFIG_BOOTLOADER_ENABLE  0xC5 // Enable ROM boot loader
#define SET_CCFG_MODE_CONF_SCLK_LF_OPTION 0x3 // LF RCOSC
//---- Use default values for all others ----
#include "<project-path>/source/ti/devices/<device>/startup_files/ccfg.c"

OAD下载

进度

CC1352R1

谢谢支持

  • 微信二维码:

选购VPS

  • 这里选择尝试使用Linode来做VPS,如果预算购的可以选择高配,一般可以选择Standard Linode plan10刀一月,我只选了Nanodes5刀一月,具体参数请查看它的官网,注册时可以提供这个推荐码ad40d846b4e9fcb9cec7a0f3e47fe553e8c2a27d有优惠.
  • 这里选择安装Debian 10,区域就选择SGJP,勾选Private IP还会有一个v4的IP,现在能供IPv4的厂商很少了,像Vultr最便宜的VPS是2.5刀一月,只提供IPv6.完成之后,控制台如下图:
    vps
  • 就上面区域选择,理论上离自己近的访问会最快,但是我在实际应用中选择了一个SG很慢,这里在创建前可以使用https://www.linode.com/speed-test/测试一下,自己本地到Linode全球各机房的速度,选最快的.安装完成可以把VPS里的IP地址使用https://tools.ipip.net/traceroute.php检查一下路由,会在下方有直观的线路地图显示,如果发现IP的线路不满意删除重建一个新的VPS.
  • 登录它有两种SSH方式,一是直接SSH访问:ssh root@xxx.xxx.xxx.xxx,这里可以使用在布署时添加RSA证书验证免密访问.二是通过Lish访问,估计它像是一个串口重定向一样的:ssh -t <username>@lish-singapore.linode.com <host-tags>,这里要用[Linode](https://www.linode.com/?
    r=ad40d846b4e9fcb9cec7a0f3e47fe553e8c2a27d)的用户名与密码登录,后面再输入VPS的用户名与密码登入VPS.

开启SSH动态转发

1
2
3
4
~$ ssh -D 1088 -f -C -q -N user@<vps-ip>

~$ ps -ef | grep ssh
user 14609 1 0 23:32 ? 00:00:00 ssh -CfNq -D 1088 user@example.com
  • 开启ssh反向代理, 把本地的22端口反向映射到vps-ip:9980,这样访问9980就是访问到目标机的22端口。
1
~$ ssh -R 9980:localhost:22 -f -C -q -N user@<vps-ip>
  • 这里一般建议修改SSH服务器的默认端22为其它数字.,参数说明:
    • -D [bind_address:]port 监听本地端口与SSH服务器创建一条Socks5通道.
    • -C 开启数据压缩功能.
    • -ffork一个进程到后台模式,不会出现Shell.
    • -N 保持连接,端口转发中有用.
    • -q 安静模式,屏蔽一些警告与错误信息.

使用ngrok隧道

  • 去到ngrok官网下载一个二进制的客户端,使用ngrok有两个场景使用,一是可以在内网把本机的某一个端口通过ngrok服务映射出去,二是可以把你的VPS服务隐藏在ngrok服务后面,再用SSH去动态转发,每次运行ngrok都会得到一个动态域名与端口,相对来说,中动态安全。下面示例是把本机的22通过ngrok
1
2
3
4
5
6
~$ ngrok tcp 22
Try our new native Go library: https://github.com/ngrok/ngrok-go
[...]
Web Interface http://127.0.0.1:4040
Forwarding tcp://8.tcp.ngrok.io:19192 -> localhost:22

  • 再用ssh动态转发,这样就把自已的vps隐藏,并且还加速了,有很多直接SSHVPS速度比较慢的。
1
~$ ssh -D 1080  user@8.tcp.ngrok.io  -p 19192

申请Let's Ecrypt证书

  • Linode API参考

  • lego Let’s Encrypt client and ACME library written in Go

  • 这里会使用lego工具通过DNS认证申请一个安全证书。

创建Access Token

  • 进入到Cloud Manager -> My Profile -> API Tokens创建,具体可以参照这里

使用LEGO申请

1
2
3
~$ git clone https://github.com/go-acme/lego
~$ cd lego
~$ make build
  • 使用dns方式,申请成功后,默认会在~/.lego/certificates有相关域名的证书文件。
1
~$ LINODE_TOKEN=<your token api>  lego --email <your email>@mail.com --dns linode --domains <linode name>.members.linode.com --tls run

通过acme.sh申请

  • acmesh-official/acme.sh

  • Secure a Website or Domain with Let’s Encrypt and acme.sh

  • 客户在申请Let’s Encrypt证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:

    • dns-01:给域名添加一个DNS TXT记录。
    • http-01:在域名对应的Web服务器下放置一个HTTP well-known URL资源文件。
    • tls-sni-01:在域名对应的Web服务器下放置一个HTTPS well-known URL资源文件。
  • 而申请通配符证书,只能使用dns-01的方式.

  • acme.sh是一个纯粹用Shell(Unix shell)语言编写的ACME协议客户端。完整的ACME协议实施。支持 ACME v1ACME v2,ACME v2支持通配符证书。并且无需root/sudoer的访问权限 。支持在Docker内使用,支持IPv6

1
2
~$ curl  https://get.acme.sh | sh
~$ echo "alias acme.sh=~/.acme.sh/acme.sh" >> ~/.bashrc

申请证书

  • 使用dns的验证方式,如果提示要一个email,需要加上--register-account -m <you email>@mail.com
1
2
~$ export LINODE_V4_API_KEY="<you linode api token >"
~$ acme.sh --issue --dns dns_linode_v4 --dnssleep 90 --debug -d <linode-name>.members.linode.com
  • 使用http的验证方式,这里没有安装任何web服务器,使用了socat工具与--standalone方式。申请成功后,会在~/.wwwroot/<linode-name>.members.linode.com目录下有相关的证书文件。

    1
    2
    3
    4
    5
    ~$ apt-get install socat
    ~$ ETH0_IPv4=`ip addr show dev eth0 | grep "inet" | head -n1 | awk '{print $2}' | awk -F '/' '{print $1}'`
    ~$ DOMAIN=`dig -x ${ETH0_IPv4} | grep "PTR" | grep -v '^;' | awk '{print $5}'`
    ~$ DOMAIN=`echo ${DOMAIN%?}`
    ~$ acme.sh --issue --standalone -d ${DOMAIN} --webroot ~/.wwwroot/${DOMAIN}
  • 安装自动刷新证书脚本定时任务

1
2
3
4
5
6
7
root@localhost:~# acme.sh --upgrade --auto-upgrade
[Sun 28 Aug 2022 01:46:57 PM UTC] Already uptodate!
[Sun 28 Aug 2022 01:46:57 PM UTC] Upgrade success!

root@localhost:~# crontab -l
26 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

  • 安装证书,以Nginx的证书加载位置为例。它会通过脚本复制证书文件到指定的目录下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ~$ cat >install_nginx_ssl.sh<<EOF

    #!/bin/bash

    domain=exmaple.com
    headscale_dir=/etc/nginx/ssl/${domain}_ecc
    [[ ! -d ${headscale_dir} ]] && mkdir -pv ${headscale_dir}
    /root/.acme.sh/acme.sh --install-cert -d ${domain} \
    --key-file ${headscale_dir}/${domain}.key \
    --fullchain-file ${headscale_dir}/fullchain.cer \
    --reloadcmd "service nginx force-reload"
    EOF
  • 如果上述出现任何错误,无法申请到证书,需要先确定是否本机的防火墙阻止了80,443的端口,或者指定一个其它的端口。

安装HeadScale

headscale-ui相关

源码安装

1
2
~$ git clone https://github.com/juanfont/headscale
~$ cd headscale && make build

Docker运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
~$ ~/headscale$ tree
.
├── config
│   ├── config.yaml
│   ├── db.sqlite
│   ├── noise_private.key
│   └── private.key
├── data
└── docker-compose.yml

~/headscale$ cat docker-compose.yml
version: '3.5'
services:
headscale:
image: headscale/headscale:latest
volumes:
- ./config:/etc/headscale/
- ./data:/var/lib/headscale
ports:
- 8080:8080
command: headscale serve
restart: unless-stopped
headscale-ui:
image: ghcr.io/gurucomputing/headscale-ui:latest
restart: unless-stopped
container_name: headscale-ui
ports:
- 9443:443
  • headscale-ui创建一个可以访问的Api Key. 打开https://headscale.example.com/web输入下面的值串。
1
2
~$ docker exec headscale-<docker> headscale apikeys create
dfjz2unKKA.N1zeAPfMIUDJWYDgaOtIX6pk1hzxxxxxxxxxxx
  • config.yaml模版来自与这里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
vpsuser@localhost:~/headscale$ grep -v '^#\|^    #\|^  #\|^$' config/config.yaml
---
server_url: https://headscale.example.com:443
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
private_key_path: ./private.key
noise:
private_key_path: ./noise_private.key
ip_prefixes:
- fd7a:115c:a1e0::/48
- 100.64.0.0/10
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
urls:
- https://controlplane.tailscale.com/derpmap/default
paths: []
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
db_type: sqlite3
db_path: ./db.sqlite
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: ./cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""
log:
format: text
level: info
acl_policy_path: ""
dns_config:
override_local_dns: false
nameservers:
- 1.1.1.1
domains: []
magic_dns: false // 不要开启,它会修改本机的/etc/resolve.conf
base_domain: example.com
unix_socket: ./headscale.sock
unix_socket_permission: "0770"
logtail:
enabled: false
randomize_client_port: false

  • 创建用户
1
2
~$ headscale users create vps1
~$ headscale users create vps2
  • 查看
1
2
3
4
5
6
7
8
9
~$ docker exec headscale-headscale-1 headscale   users list
ID | Name | Created
1 | vps1 | 2023-02-01 08:34:30
2 | vps2 | 2023-02-01 08:34:34
3 | vps3 | 2023-02-03 15:51:40
4 | vps5 | 2023-02-24 08:54:40
5 | vps6 | 2023-02-24 09:05:33
6 | vps7 | 2023-02-25 07:29:03

  • 查看路由
1
2
3
4
5
6
7
8
9
10
~$ docker exec headscale-headscale-1 headscale routes list
An updated version of Headscale has been found (0.22.0-alpha2 vs. your current 0.21.0). Check it out https://github.com/juanfont/headscale/releases
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | | 192.168.10.0/24 | false | false | false
2 | | 10.0.0.0/24 | false | false | false
3 | debian-xyz97cy4 | 192.168.1.0/24 | false | false | false
4 | debian | 10.0.0.0/24 | true | true | true
5 | xx-debian | 10.0.0.0/24 | false | false | false
6 | xx-debian | 0.0.0.0/0 | true | false | -
7 | xx-debian | ::/0 | true | false | -
  • 查看要结点列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
~$ docker exec headscale-headscale-1 headscale nodes list
An updated version of Headscale has been found (0.22.0-alpha2 vs. your current 0.21.0). Check it out https://github.com/juanfont/headscale/releases
ID | Hostname | Name |MachineKey| NodeKey | User | IP addresses | Ephemeral | Last seen | Expiration | Online | Expired
2 | debian | debian-xyz9 | [8uJXG] | [5H4BE] | vps2 | 100.64.0.2, fd7a:115c:b1e0::2 | false | 2023-04-15 13:57:53 | 0001-01-01 00:00:00 | online | no
3 | debian | debian-sbsb | [62pMK] | [6Dz24] | vps3 | 100.64.0.3, fd7a:115c:b1e0::3 | false | 2023-02-10 03:48:02 | 0001-01-01 00:00:00 | offline | no
4 | debian | debian-d9l5 | [N81bK] | [z5uBc] | vps3 | 100.64.0.4, fd7a:115c:b1e0::4 | false | 2023-04-15 13:57:57 | 0001-01-01 00:00:00 | online | no
5 | Galaxy A9 | galaxy-a9-2 | [J+Qwv] | [KPeSZ] | vps5 | 100.64.0.5, fd7a:115c:b1e0::5 | false | 2023-03-28 04:00:16 | 0001-01-01 00:00:00 | offline | no
7 | DESKTOP-VO| desktop-6pr | [tujxu] | [WmkOH] | winhome | 100.64.0.7, fd7a:115c:b1e0::7 | false | 2023-04-08 07:43:34 | 0001-01-01 00:00:00 | offline | no
8 | 51-debian | 51-debian | [JIXKw] | [aCF/i] | build | 100.64.0.8, fd7a:115c:b1e0::8 | false | 2023-04-15 13:58:16 | 0001-01-01 00:00:00 | online | no
9 | debian | debian | [q6B+J] | [tNRfk] | vps1 | 100.64.0.1, fd7a:115c:b1e0::1 | false | 2023-04-15 13:58:17 | 0001-01-01 00:00:00 | online | no
10 | pine64 | pine64 | [Qz+wP] | [ooL1m] | vps2 | 100.64.0.9, fd7a:115c:b1e0::9 | false | 2023-03-20 12:03:20 | 0001-01-01 00:00:00 | offline | no
11 | pine64 | pine64-qpos | [BFqoJ] | [9e/fx] | pine64 | 100.64.0.10, fd7a:115c:b1e0::a | false | 2023-03-21 15:43:39 | 0001-01-01 00:00:00 | offline | no
12 | pine64 | pine64-7rj4 | [TyQ60] | [sv+cn] | pine64 | 100.64.0.11, fd7a:115c:b1e0::b | false | 2023-04-15 13:57:51 | 0001-01-01 00:00:00 | online | no
13 | debian | debian-yaia | [T4D+u] | [JHtyJ] | mini | 100.64.0.12, fd7a:115c:b1e0::c | false | 2023-04-15 10:10:43 | 0001-01-01 00:00:00 | offline | no

安装Tailscale

源码编译Linux

  • Linux amd64

    1
    2
    3
    4
    5
    ~$ git clone https://github.com/tailscale/tailscale
    ~$ cd tailscale
    ~$ GOOS=linux GOARCH=amd64 ./tool/go install tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaled
    ~$ GOOS=linux GOARCH=amd64 ./tool/go build -o ./dist tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaled

  • Linux arm32

1
~$ GOOS=linux GOARCH=arm GOARM=7 ./tool/go build -o ./dist  tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaled

运行

  • 直接命令行运行,先要让tailscaled进程运行起来。
1
~$ sudo tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=41641  -no-logs-no-support
  • 也可以使用systemd服务,在tailscale/cmd/tailscaled目录下有各种服务的模版文件,如:tailscaled.openrc,tailscaled.service,tailscaled.defaults等。

  • 复制tailscaled默认参数配置

1
2
3
4
~$ grep -v '^#\|^$' /etc/default/tailscaled
PORT="41641"
FLAGS="-no-logs-no-support"

  • 具体的进程服务的配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
~$ cat /etc/systemd/system/tailscaled.service
[Unit]
Description=Tailscale node agent
Documentation=https://tailscale.com/kb/
Wants=network-pre.target
After=network-pre.target NetworkManager.service systemd-resolved.service

[Service]
EnvironmentFile=/etc/default/tailscaled
ExecStartPre=/usr/sbin/tailscaled --cleanup
ExecStart=/usr/sbin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} $FLAGS
ExecStopPost=/usr/sbin/tailscaled --cleanup

Restart=on-failure

RuntimeDirectory=tailscale
RuntimeDirectoryMode=0755
StateDirectory=tailscale
StateDirectoryMode=0700
CacheDirectory=tailscale
CacheDirectoryMode=0750
Type=notify

[Install]
WantedBy=multi-user.target

登录服务器

  • 这里运行登录,会在终端输出一行参数的提示,或者会自动打开本地浏览器,输出一段参数,需要在headscale上去运行。
1
~$ sudo tailscale up --login-server <your server url or ip:port>
  • 上面运行输出的参数,需要在headscale的服务器上运行。
1
~$ sudo headscale --user vps1 nodes register  --key nodekey:ee91f2883a532cff2ea63991cfxxxxx
  • 如果headscale是运行在docker里的,需要把命令传入到docker.
1
~$ docker exec headscale-<docker> headscale nodes register --user vps1 --key nodekey:ee91f2883a532cff2ea63991cfxxxxx
  • 重新登录
1
2
3
4
5
6
~$ sudo tailscale logout
~$ sudo tailscale up --operator=$USER --login-server=https://headscale.example.com
To authenticate, visit:

https://headscale.example.com:443/register/nodekey:0a101ba73ba0ad5ab17984da614e7d52c8089d298429534713baxxxxxxxxx

  • 另一种登录方式,先在headscale上,为一个用户生成preauthkeys,再拿这一串key到客户端进行登录
1
2
~$ docker exec headscale-headscale-1 headscale --user vps2 preauthkeys create --reusable --expiration 24h
e770e03d374e667134de22b8ccxxxxxx
  • 去某一个客户端机器登录认证。
1
~$ sudo tailscale up --login-server https://headscale.example.com --authkey e770e03d374e667134de22b8ccxxxxxx
  • 测试与对端是否是p2p直连
1
2
3
4
5
6
7
8
9
10
11
12
13
~$ tailscale ping 100.64.0.1
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 346ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 346ms
pong from debian (fd7a:115c:a1e0::1) via DERP(tok) in 2.671s
pong from debian (fd7a:115c:a1e0::1) via DERP(tok) in 483ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 347ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 346ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 345ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 345ms
pong from debian (fd7a:115c:a1e0::1) via DERP(hkg) in 343ms
pong from debian (fd7a:115c:a1e0::1) via DERP(tok) in 1.62s
direct connection not established

  • 检测网络状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
~$ tailscale netcheck

Report:
* UDP: true
* IPv4: yes, 120.235.xxx.157:42608
* IPv6: yes, [2409:xxx:2418:b130:xxx:3815:55ca:xxx]:6886
* MappingVariesByDestIP: false
* HairPinning: false
* PortMapping:
* CaptivePortal: false
* Nearest DERP: Hong Kong
* DERP latency:
- hkg: 74.6ms (Hong Kong)
- sin: 132.2ms (Singapore)
- tok: 152ms (Tokyo)
- syd: 155.4ms (Sydney)
- sea: 221.2ms (Seattle)
- lax: 223.3ms (Los Angeles)
- sfo: 233ms (San Francisco)
- lhr: 233.1ms (London)
- ams: 236.6ms (Amsterdam)
- den: 244.3ms (Denver)
- ord: 248.2ms (Chicago)
- dfw: 251.7ms (Dallas)
- blr: 252.3ms (Bangalore)
- par: 255ms (Paris)
- fra: 255.2ms (Frankfurt)
- waw: 260.5ms (Warsaw)
- tor: 264.9ms (Toronto)
- hnl: 266.4ms (Honolulu)
- mia: 275.1ms (Miami)
- dbi: 275.5ms (Dubai)
- nyc: 277.4ms (New York City)
- mad: 287.6ms (Madrid)
- sao: 368ms (São Paulo)
- jnb: 424.2ms (Johannesburg)

  • 不修改本地/etc/resolv.conf.
1
~$ tailscale set --accept-dns=false
  • 查看本地路由
1
2
3
4
5
6
7
8
~$ ip route show table 52
100.64.0.1 dev tailscale0
100.64.0.3 dev tailscale0
100.64.0.4 dev tailscale0
100.64.0.5 dev tailscale0
100.64.0.6 dev tailscale0
100.64.0.7 dev tailscale0
[...]

打通局域网访问

  • 首先需要在开放访问的局域网的机器上开启内核路由转发
1
2
3
echo 'net.ipv4.ip_forward = 1' | tee /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf
sysctl -p
  • 在注册启动节点时加入--advertise-routes=xxx.xx.xx.x/xx通告声明本局域网的路由
1
~$ tailscale up --login-server=https://headscale.example.com --accept-dns=false --advertise-routes=10.0.1.0/24 --reset
  • headscale查看并开启相应的路由

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ~$ docker exec headscale-headscale-1 headscale routes list
    An updated version of Headscale has been found (0.22.0-alpha2 vs. your current 0.21.0). Check it out https://github.com/juanfont/headscale/releases
    ID | Machine | Prefix | Advertised | Enabled | Primary
    1 | | 192.168.10.0/24 | false | false | false
    2 | | 10.0.0.0/24 | false | false | false
    3 | debian-xyz97cy4 | 192.168.1.0/24 | false | false | false
    4 | debian | 10.0.1.0/24 | true | false | true
    5 | xx-debian | 10.0.1.0/24 | false | false | false
    6 | xx-debian | 0.0.0.0/0 | true | false | -
    7 | xx-debian | ::/0 | true | false | -
  • 如上图所示,第4行Enabled显示是false,这里需要开启它。

1
2
3
4
5
6
~$ docker exec headscale-headscale-1 headscale routes enable -r 4

~$ docker exec headscale-headscale-1 headscale routes list
[...]
4 | debian | 10.0.1.0/24 | true | true | true
[...]
  • 去其它节点本看路由结果,节点启时需要加入--accept-routes=true才能。
1
2
3
~$ sudo tailscale up --login-server https://headscale.example.com --accept-routes=true
~$ ip route show table 52|grep "10.0.1.0/24"
10.0.1.0/24 dev tailscale0
  • 上面的节点启动连接成功后,就可以直接在本地访问对端10.0.1.0/24网络。如下面,则时两个子局域通过各自网络的一台机器,把两个局域网连通起来。
1
2
3
4
# A局域网的一台机器。
~$ tailscale up --accept-routes=true --accept-dns=false --advertise-routes=192.168.1.0/24
# B局域网的一台机器。
~$ tailscale up --accept-routes=true --accept-dns=false --advertise-routes=192.168.2.0/24

设置exit-node.

  • 首先需要一台机器在注册启动节点时加入--advertise-exit-node声明它提供节点出口服务。已经注册的可以命名用下面命令:

    1
    ~$  sudo tailscale set --advertise-exit-node
  • 需要在headscale中开启0.0.0.0/0,::/0路由,

1
2
3
~$ docker exec headscale-headscale-1 headscale routes enable -r 6
~$ docker exec headscale-headscale-1 headscale routes enable -r 7

  • 查看路由
1
2
3
4
5
6
7
8
9
~$ docker exec headscale-headscale-1 headscale routes list
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | | 192.168.10.0/24 | false | false | false
2 | | 10.0.0.0/24 | false | false | false
3 | debian-xyz97cy4 | 192.168.1.0/24 | false | false | false
4 | debian | 10.0.0.0/24 | true | true | true
5 | xx-debian | 10.0.0.0/24 | true | false | false
6 | xx-debian | 0.0.0.0/0 | true | true | -
7 | xx-debian | ::/0 | true | true | -
  • 其它节点,设置使用exit-node做为出口路由
1
~$ sudo tailscale up --login-server https://headscale.example.com  --exit-node=100.64.0.8
  • 或者
1
~$ sudo tailscale set --exit-node xx-debian
  • 退出使用exit-node出口路由
1
~$ sudo tailscale set --exit-node ""

Windows客户端

Android客户端

  • tailscale-android的安卓端,可以从源码编译,可以从F-Droid或者从Google Play两个市场上安装。

  • 1.29.1开始可以支持custom server,它的入口比较了隐蔽,需点击右上角的三的个点,查看三次about,第四次才会出现这更改服务器的菜单。登录注册流程与Linux类似。

安装Trojan

  • trojan是一个代理上网工具,能帮助学习到更全面的知识,同时它的服务请求是通过标准的SSL(443)通讯的.对于新手可以去到Github找一键安装脚本,有动手能力的可以自己编译源码与配置.

网络性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
~$ vi /etc/security/limits.conf

# 打开文件,添加下面的行.

* soft nofile 1048576
* hard nofile 1048576

# for server running in root:
root soft nofile 1048576
root hard nofile 1048576

~$ sudo cat > '/etc/sysctl.d/99-sysctl.conf' << EOF
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter = 1
# Overrule forwarding behavior. Accept Router Advertisements
net.ipv6.conf.all.accept_ra = 2
# max open files
fs.file-max = 1048576
# max read buffer
net.core.rmem_max = 67108864
# max write buffer
net.core.wmem_max = 67108864
# default read buffer
net.core.rmem_default = 65536
# default write buffer
net.core.wmem_default = 65536
# max processor input queue
net.core.netdev_max_backlog = 409600
# max backlog
net.core.somaxconn = 4096
# resist SYN flood attacks
net.ipv4.tcp_syncookies = 1
# reuse timewait sockets when safe
net.ipv4.tcp_tw_reuse = 1
# short FIN timeout
net.ipv4.tcp_fin_timeout = 30
# short keepalive time
net.ipv4.tcp_keepalive_time = 1200
# outbound port range
net.ipv4.ip_local_port_range = 6000 65535
# max timewait sockets held by system simultaneously
net.ipv4.tcp_max_tw_buckets = 5000
# turn on TCP Fast Open on both client and server side
net.ipv4.tcp_fastopen = 3
# TCP receive buffer
net.ipv4.tcp_rmem = 4096 87380 67108864
# TCP write buffer
net.ipv4.tcp_wmem = 4096 65536 67108864
# turn on path MTU discovery
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_max_syn_backlog = 12800
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
~$ sudo sysctl -p

申请证书Let's Encrypt

  • 这里使用一个简单脚本获取

    1
    2
    3
    4
    5
    6
    ~$ sudo apt-get install certbot dnsutils  python-certbot-nginx -y
    ~$ ETH0_IPv4=`ip addr show dev eth0 | grep "inet" | head -n1 | awk '{print $2}' | awk -F '/' '{print $1}'`
    ~$ DOMAIN=`dig -x ${ETH0_IPv4} | grep "PTR" | grep -v '^;' | awk '{print $5}'`
    ~$ DOMAIN=`echo ${DOMAIN%?}`
    ~$ certbot certonly --nginx --agree-tos --email yjdwbj@gmail.com -d $DOMAIN
    ~$ apt-get autoremove nginx-full -y # 这里没有用到nginx,删除它.
  • 申请成功后,查看证书.

    1
    2
    ~# ls/etc/letsencrypt/live/<xxxxx>.members.linode.com
    cert.pem chain.pem fullchain.pem privkey.pem README

部署Trojan

  • 这里就直接下载一个最新的Release解压使使用,解压后如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ~# tree trojan
    trojan
    ├── config.json
    ├── CONTRIBUTORS.md
    ├── examples
    │   ├── client.json-example
    │   ├── forward.json-example
    │   ├── nat.json-example
    │   ├── server.json-example
    │   └── trojan.service-example
    ├── LICENSE
    ├── README.md
    └── trojan
  • 这里直接从examples/server.json-example复制一个改名成server.json,具体修改的位置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    # cat server.json
    {
    "run_type": "server", # 如果是用客户端,改成client
    "local_addr": "0.0.0.0",
    "local_port": 443,
    "remote_addr": "127.0.0.1",
    "remote_port": 80,
    "password": [
    "passwd1", # 可以设置多个密码,可以使用任意一个访问该服务.
    "passwd2"
    ],
    "log_level": 1,
    "ssl": {
    # 下面这两行,就是使用从letsencrypt申请到的证书的完全路径.
    "cert": "/etc/letsencrypt/live/<xxxxxx>.members.linode.com/fullchain.pem",
    "key":"/etc/letsencrypt/live/<xxxxx>.members.linode.com/privkey.pem",
    "key_password": "",
    "cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384",
    "cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
    "prefer_server_cipher": true,
    "sni": "yourdomain", //如果客户端,会有这一行,就是服务器的域名.
    "alpn": [
    "h2",
    "http/1.1"
    ],
    "reuse_session": true,
    "session_ticket": false,
    "session_timeout": 600,
    "plain_http_response": "",
    "curves": "",
    "dhparam": ""
    },
    "tcp": {
    "prefer_ipv4": false,
    "no_delay": true,
    "keep_alive": true,
    "reuse_port": true,
    "fast_open": true, // 要使用 sysctl -w net.ipv4.tcp_fastopen=4
    "fast_open_qlen": 20
    },
    "mysql": {
    "enabled": false,
    "server_addr": "127.0.0.1",
    "server_port": 3306,
    "database": "trojan",
    "username": "trojan",
    "password": ""
    }
    }

配置systemd启动与运行权限

  • 使用一个非特权用户运行

    1
    2
    3
    ~# useradd -s /usr/sbin/nologin trojan
    ~# chown -R trojan:trojan /path/to/trojan
    ~# chmod u+x /path/to/trojan
  • 或者使用Capabilities来管理根限.如果不是特权用户是不绑定1024以下的端口的.

    1
    ~# setcap 'cap_net_bind_service=+eip' /path/to/trojan
  • 创建文件,/etc/systemd/system/trojan.service或者/lib/systemd/system/trojan.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~$ cat /etc/systemd/system/trojan.service
[Unit]
Description=Trojan
After=network.target network-online.target nss-lookup.target

[Service]
User=trojan
Group=trojan
Restart=on-failure
Type=simple
ExecStart=/path/to/trojan -c /path/to/config.json

[Install]
WantedBy=multi-user.target

~$ sudo systemctl enable trojan
~$ sudo systemctl start trojan
  • 上面启动如果有错,使用systemctl status trojan再用journalctl -x | grep "trojan" -A +10查看具体错误原因.

##TLS1.3支持

  • 如果系统的openssl版本是在1.1.1以上的可以开启TLS1.3,加密可以改成如下:
    1
    TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

使用Docker安装

  • 主机上获取证书
    1
    2
    ~$ certbot certonly --nginx  --agree-tos --email yjdwbj@gmail.com  -d proxy.yjdwbj.cloudns.org --force-interactive
    ~$ chmod 644 /etc/letsencrypt/archive/proxy.yjdwbj.cloudns.org/privkey.pem

安装dnsmasq来加速解析(非必需)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~$ sudo apt-get install dnsmasq -y
~$ sudo cat > '/etc/dnsmasq.conf' << EOF
port=53
domain-needed
bogus-priv
enable-ra # 开启IPv6 delegation prefix
no-resolv
server=8.8.4.4#53
server=1.1.1.1#53
interface=lo
bind-interfaces
cache-size=10000
no-negcache
log-queries
log-facility=/var/log/dnsmasq.log
EOF

~$ sudo echo "nameserver 127.0.0.1" > /etc/resolv.conf || true
~$ sudo chattr +i /etc/resolv.conf || true
~$ sudo systemctl enable dnsmasq

使用Dokku安装

1
2
3
4
5
6
7
8
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nextcloud latest 7aa569922593 14 hours ago 835MB
gliderlabs/herokuish latest 61872ca570ac 2 days ago 1.35GB
gliderlabs/herokuish v0.5.26 61872ca570ac 2 days ago 1.35GB
shadowsocks-libev latest cf7d25b78191 2 months ago 66.1MB
trojan latest 8fc0996f16f6 2 months ago 11.5MB
[....]
1
2
3
4
5
6
7
8
9
~$ dokku apps:create trojan
~$ dokku domains:add trojan proxy.llccyy.dynv6.net
~$ dokku config:set trojan --no-restart DOKKU_LETSENCRYPT_EMAIL=yjdwbj@gmail.com
~$ dokku letsencrypt trojan
~$ dokku storage:mount trojan /etc/trojan:/etc/trojan
#
~$ dokku storage:mount trojan /home/dokku/trojan/letsencrypt:/etc/letsencrypt
~$ docker tag trojan:latest dokku/trojan:latest
~$ dokku tags:deploy trojan latest

安装WireGuard

  • 现在WireGuard还没有进入Debian的稳定版本分支,需要使用下面命令安装.
1
2
3
4
5
6
~# echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
~# printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' > /etc/apt/preferences.d/limit-unstable
~# uname -a
Linux localhost 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) x86_64 GNU/Linux
~# apt update
~# apt install linux-headers-4.19.0-6-amd64 wireguard-dkms wireguard-tools
  • 如果安装了WireGuard dkms模块了,但是又更新内核,这是是需要用重新编译并安装到新的内核里,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~$ dkms status
[.....]
wireguard, 0.0.20200215, 5.5.5-20200223-lcy, x86_64: installed
sudo dkms build -m wireguard -v 0.0.20200215
Kernel preparation unnecessary for this kernel. Skipping...
Building module:
cleaning build area...
[.....]
cleaning build area...
DKMS: build completed.
~$ sudo dkms install -m wireguard -v 0.0.20200215
wireguard.ko:
[...]
depmod...
DKMS: install completed.

配置服务器

1
2
3
4
5
6
7
8
9
10
11
~$ cd /etc/wireguard/
~$ sudo wg genkey | tee privatekey | wg pubkey > publickey
~$ sudo cat > '/etc/wireguard/wg0.conf' << EOF
[Interface]
PrivateKey = <Private Key>
Address = 172.18.0.1/24, fd86:ea04:1115::1/64
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
SaveConfig = true
EOF

安装防火墙

1
2
3
4
5
~$ sudo apt-get install ufw
~$ sudo ufw allow 22/tcp
~$ sudo ufw allow 51820/udp
~$ sudo ufw enable
~$ sudo ufw status verbose

启动WireGuard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~$ sudo wg-quick up wg0
~$ sudo systemctl enable wg-quick@wg0
~$ sudo wg show
public key: DSdXQC01TD7Hk9sXXUKjevzJv6md+aK0x7/aKrmJMX8=
private key: (hidden)
listening port: 51820
~$ ifconfig wg0
ifconfig wg0
wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1420
inet 172.18.0.1 netmask 255.255.255.0 destination 172.18.0.1
inet6 fd86:ea04:1115::1 prefixlen 64 scopeid 0x0<global>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

客户端

  • 客户端的安装方式如同服务端,VPN的配置都是对等配置,就是都要知道对方的公共密钥.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ~$ cd /etc/wireguard/
    ~$ sudo wg genkey | tee privatekey | wg pubkey > publickey
    ~$ sudo cat > '/etc/wireguard/wg0.conf' << EOF
    [Interface]
    PrivateKey = <Private Key>
    Address = 172.18.0.2/24, fd86:ea04:1115::5/64
    [Peer]
    PublicKey= <Server Public Key>
    Endpoint = <Server IpAddress>:51820
    AllowedIPs = 172.18.0.2/24,fd86:ea04:1115::0/64
    EOF
    ~$ sudo wg-quick up wg0
    interface: wg0
    public key: <Public Key>
    private key: (hidden)
    listening port: 41743

服务端添加Peer

  • 上面就是配置好的客户端,但是还不能连接到上述的服务器去,现在还要在服务端里加上对等的Peer项,可以直接编辑服务端的/etc/wireguard/wg0.conf,也可以使用下面命令.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
~$ sudo wg set wg0 peer <Client Public Key> allowed-ips 172.18.0.2/32
~$ sudo wg-quick save wg0 # 保存配置
~$ sudo wg
interface: wg0
public key: <Server Public Key>
private key: (hidden)
listening port: 51820

peer: <Client Public Key>
endpoint: <Client Public IpAddress>:<port>
allowed ips: 172.18.0.0/24, fd86:ea04:1115::/64
latest handshake: 2 hours, 44 minutes, 13 seconds ago
transfer: 3.16 MiB received, 13.16 MiB sent

~# cat /etc/wireguard/wg0.conf
Interface]
Address = 172.18.0.1/16
Address = fd86:ea04:1115::1/64
SaveConfig = true
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = <public key of server>

[Peer]
PublicKey = <public key of client B>
AllowedIPs = 172.18.0.2/32
Endpoint = <public ip of Client B>:23637

[Peer]
PublicKey = <public key of client A>
AllowedIPs = 172.18.0.3/32
Endpoint = <public ip of Client A>:33506
  • 如果无错连接成功后,就可以从172.18.0.1ping 172.18.0.2.
  • 下面是一个服务器连接两个端点的配置:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ~$ wg show
    interface: wg0
    public key: <server >
    private key: (hidden)
    listening port: 51820

    peer: <public key of Bob>
    endpoint: <Bob>:33506
    allowed ips: 172.18.0.3/32
    latest handshake: 50 seconds ago
    transfer: 35.55 KiB received, 36.31 KiB sent

    peer: <public key of Alice>
    endpoint: <Alice>:23637
    allowed ips: 172.18.0.2/32
    latest handshake: 2 minutes, 51 seconds ago
    transfer: 15.53 KiB received, 14.59 KiB sent

手机端通过QR加入服务器

  • Generating WireGuard QR codes for fast mobile deployments

  • 这里可以完全在服务端完成,现生成一组服务器的密钥对, 再建一个名为clients目录,在下面生成各个客户端的密钥与配置文件再把配置文件转成终端的QR图,供手机端扫码加入.

    1
    ~$ sudo mkdir -p /etc/wireguard/clients; wg genkey | sudo tee /etc/wireguard/clients/mobile.key | wg pubkey | sudo tee /etc/wireguard/clients/mobile.key.pub
  • 生成配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ~$ cat > /etc/wireguard/clients/mobile.conf <<EOF
    [Interface]
    PrivateKey = <mobile.key>
    Address = 10.0.0.10/24
    DNS = 1.1.1.1, 1.0.0.1

    [Peer]
    PublicKey = YOUR_SERVER_PUBLIC_KEY
    AllowedIPs = 0.0.0.0/0
    Endpoint = YOUR_SERVER_WAN_IP:51820
    EOF

  • 转换成QR图

1
~$ qrencode -t ansiutf8 < /etc/wireguard/clients/mobile.conf
  • 服务端加入该客户端并保存.
    1
    2
    ~$ sudo wg set wg0 peer <mobile.key.pub> allowed-ips 0.0.0.0/0
    ~$ sudo wg-quick save wg0

安装PolipoHTTP Proxy

  • Polipo
    1
    2
    3
    4
    5
    6
    7
    ~# cat > /etc/polipo/config <<EOF
    proxyAddress = "0.0.0.0"
    allowedClients=172.18.0.0/24,127.0.0.1,192.168.1.0/24
    socksParentProxy = "127.0.0.1:1080"
    EOF

    ~$ sudo systemctl restart polipo

安装V2Ray

简单脚本安装

  • 参照这里直接下载解压二进制的安装,不知会不会夹带私货.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    ~$ bash <(curl -L -s https://install.direct/go.sh)
    Installing V2Ray v4.22.1 on x86_64
    Downloading V2Ray: https://github.com/v2ray/v2ray-core/releases/download/v4.22.1/v2ray-linux-64.zip
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 608 100 608 0 0 9212 0 --:--:-- --:--:-- --:--:-- 9212
    100 11.6M 100 11.6M 0 0 24.3M 0 --:--:-- --:--:-- --:--:-- 24.3M
    awk: not an option: -e
    Archive: /tmp/v2ray/v2ray.zip
    inflating: /usr/bin/v2ray/geoip.dat
    inflating: /usr/bin/v2ray/geosite.dat
    inflating: /usr/bin/v2ray/v2ctl
    inflating: /usr/bin/v2ray/v2ray
    PORT:42747
    UUID:x009c053-xxxx-4420-xxxx-33b2fa35209x
    Archive: /tmp/v2ray/v2ray.zip
    inflating: /etc/systemd/system/v2ray.service
    Created symlink /etc/systemd/system/multi-user.target.wants/v2ray.service → /etc/systemd/system/v2ray.service.
    V2Ray v4.22.1 is installed.

源码编译安装

  • 安装合适的golang版本,具体可以查源码内的go.mod文件第一行。

    1
    2
    3
    4
    5
    ~$ sudo apt-get install golang-1.19 golang-1.19-go -y
    ~$ sudo update-alternatives --install /usr/lib/go/bin/go go /usr/lib/go-1.19/bin/go 80
    ~$ ln -svf /usr/lib/go/bin/go /usr/bin/go
    ~$ sudo update-alternatives --config go
    ~$ git clone https://github.com/v2fly/v2ray-core
  • v2ray-core编译安装方法可以使用它源码里的脚本v2ray-core/user-package.sh来运行即可,也可以直接运行v2ray-core/install-release.sh安装官方编译的版本。

  • 使用v2ray-core/user-package.sh编译的默认会生成一个如下的zip文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
unzip ../v2ray-custom-amd64-linux-20220902-230653.zip
Archive: ../v2ray-custom-amd64-linux-20220902-230653.zip
inflating: vpoint_vmess_freedom.json
inflating: vpoint_socks_vmess.json
inflating: geoip.dat
inflating: geosite.dat
inflating: v2ray
inflating: config.json
inflating: geoip-only-cn-private.dat
creating: systemd/
creating: systemd/system/
inflating: systemd/system/v2ray.service
inflating: systemd/system/v2ray@.service
  • 需要系统控制服务,把v2ray.serveice复制到相应的系统目录下。

编译windows的客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
~$ git clone https://github.com/v2fly/v2ray-core
~$ cd v2ray-core/release
~$ ln -svf ../../v2ray-core .
~$ cd ../
~$ sed -i 's/^nosource=0/nosource=1/g' release/user-package.sh
~$ sed -i 's/^GOARCH=arm/GOARCH=386/g' release/user-package.sh
~$ ./user-package.sh windows

Build ARGS: GOOS=windows GOARCH=386 CODENAME=user BUILDNAME=20230225-165708
PKG ARGS: pkg=zip
>>> Use current directory as WORKDIR
>>> Compile v2ray ...
>>> Compile v2ctl ...
>>> Download latest geoip...
>>> Download latest geosite...
>>> Copying config...
>>> Generating zip package
adding: vpoint_vmess_freedom.json (deflated 54%)
adding: vpoint_socks_vmess.json (deflated 50%)
adding: geoip.dat (deflated 77%)
adding: v2ray.exe (deflated 60%)
adding: geosite.dat (deflated 71%)
adding: wv2ray.exe (deflated 60%)
adding: config.json (deflated 60%)
adding: v2ctl.exe (deflated 60%)
adding: systemd/ (stored 0%)
>>> Generated: v2ray-custom-386-windows-20230225-165708.zip at /home/michael/3TB-DISK/github/v2ray/v2ray-core

Websockets+TLS+Nginx配置

v2ray-core服务端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
"inbounds": [
{
"port": 10000,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "$your-uuid"
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/vmess"
}
}
},
{
"port": 10001,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "$your-uuid",
"level": 0
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/vless"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
]
}

v2ray-core客户端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
{
"inbounds": [
{
"port": 1080,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"settings": {
"udp": false
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "your-server-ip-or-domain",
"port": 443,
"users": [
{
"id": "your-uuid"
}
]
}
]
},
"mux": {
"enabled": true
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"headers": {
"Host": "your-host"
},
"path": "/vmess"
},
"tlsSettings": {
"serverName": "your-server-name",
"allowInsecure": false
}
}
},
{
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "your-server-ip-or-domain",
"port": 443,
"users": [
{
"id": "your-uuid",
"encryption": "none",
"level": 0
}
]
}
]
},
"mux": {
"enabled": true
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"headers": {
"Host": "your-host"
},
"path": "/vless"
},
"tlsSettings": {
"serverName": "your-server-name",
"allowInsecure": false
}
}
},
{
"protocol": "dns",
"settings": {
"network": "tcp",
"address": "1.1.1.1",
"port": 53
}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "adblock"
}
],
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"outboundTag": "direct",
"domain": [
"geosite:cn" // 国内的站点走直连,不转发到服务器
]
},
{
"type": "field",
"ip": [
"geoip:private", // 私有地址直连,不转发到服务器
"geoip:cn" // 国内的域名走直连,不转发到服务器
],
"outboundTag": "direct"
}
]
}
}

Nginx配置

  • Nginx主要是用于websockets的反向代理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
root@localhost:~# cat /etc/nginx/sites-available/ssl
server {
listen 443 ssl;
listen [::]:443 ssl;

ssl_certificate /etc/letsencrypt/$your-server-domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$your-server-domain/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

server_name $your-server-domain;
location / {
return 204;
}

location /vmess {
proxy_redirect off;
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
# Show real IP in v2ray access.log
# proxy_set_header X-Real-IP $remote_addr;
proxy_intercept_errors on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /vless {
proxy_redirect off;
proxy_pass http://127.0.0.1:10001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
# Show real IP in v2ray access.log
# proxy_set_header X-Real-IP $remote_addr;
proxy_intercept_errors on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

Http2+TLS配置

  • 注意,这里并没有使用nginx来做前置代理,因为nginx现在还不能代理http2的请求,网上有所以这里是直接把v2ray-core的服务暴露出来。这里涉及到一些内外网分流,要用到geoip的数据做为判断,这里主要是使用geoip.datgeosite.dat,如果要更极致一点, 可以参考使用V2Ray 路由规则文件加强版

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"port": 10000,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "your-uuid" // 与客户端一定要匹配
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/vmess"
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 10001,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "your-uuid",
"level": 0
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/vless"
}
}
},
{
"port": 1443,
"listen": "<local ip4>",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "your-uuid"
}
]
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"streamSettings": {
"network": "http",
"security": "tls",
"httpSettings": {
"path": "/ray"
},
"tlsSettings": {
"certificates": [
{
"certificateFile": "/etc/letsencrypt/live/<your-server-domain>/fullchain.pem",
"keyFile": "/etc/letsencrypt/live/<your-server-domain>/privkey.pem"
}
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct",
"settings": {}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
]
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"port": 3080,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": false
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"port": 1443,
"address": "your-server-address",
"users": [
{
"id": "your-uuid" // 与服务端的对应的inbounds定义块是一致的。
}
]
}
]
},
"streamSettings": {
"network": "http",
"security": "tls",
"tag": "proxy",
"httpSettings": {
"path": "/ray"
},
"tlsSettings": {
"allowInsecure": false
}
}
},
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "adblock"
}
],
"dns": {
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org",
"your-server-address"
]
},
{
"address": "114.114.114.114",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org"
]
},
{
"address": "8.8.8.8",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
},
{
"address": "1.1.1.1",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
}
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"domain": [
"goproxy.io",
"amazon.com",
"microsoft.com",
"jd.com",
"youku.com",
"baidu.com"
],
"type": "field",
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"barkinwee.live", // 自己收集定义的一些广告网站,加入到这里来进行阻止访问。
"bestrealprizes.life",
"snapcheat16s.com",
"cloudnetstorage.com",
"hot-dating-here.life",
"glg.spign.nl",
"www.needevery.in",
"next-pops.top",
"1423.barkinwee.live",
"get-my-prize.in",
"achieve-superprizes.life",
"geosite:category-ads-all"
],
"outboundTag": "adblock"
},
{
"type": "field",
"ip": [
"geoip:private",
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
}
]
}
}
}

搭建一个中继

  • 这里中继是解决我一个手机使用的场景,手机的移动网络无法直连VPS的服务,地址的都ping不通,但是家里的宽带网络可以正常访问。所以在家里搭一个中继,使用IPv6+DDNS直接访问, 它是一个服务端又是一个客户端。可以使用一个如树莓派的单板机来足够担挡。

  • server.bridge.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    {
    "log": {
    "loglevel": "none"
    },
    "inbounds": [
    {
    "tag": "rpi",
    "port": 1443,
    "protocol": "vmess",
    "settings": {
    "clients": [
    {
    "id": "your-bridge-uuid" // 连接本机的客户端的uuid要与这里是一致的。
    }
    ]
    }
    }
    ],
    "outbounds": [
    {
    "tag": "vps",
    "protocol": "vmess",
    "settings": {
    "vnext": [
    {
    "port": 1443,
    "address": "your-server-address", // linode上VPS的uuid,它才是正真提供上网出口的服务
    "users": [
    {
    "id": "your-uuid"
    }
    ]
    }
    ]
    },
    "streamSettings": {
    "network": "http",
    "security": "tls",
    "tag": "proxy",
    "httpSettings": {
    "path": "/ray"
    },
    "tlsSettings": {
    "allowInsecure": false
    }
    }
    }
    ],
    "routing":{
    "rules":[
    {
    "type":"field",
    "inboundTag":[
    "rpi"
    ],
    "outboundTag":"vps" // 路由很重要,把rpi入站的全部转到vps出站
    }
    ]
    }
    }

  • 客户端的配置与上面其它方案类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
{
"inbounds": [
{
"port": 1080,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"udp": false
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"port": 1443,
"address": "yourdns.dynv6.net",
"users": [
{
"id": "your-bridge-uuid"
}
]
}
]
}
},
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "adblock"
}
],
"dns": {
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org"
]
},
{
"address": "114.114.114.114",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org"
]
},
{
"address": "8.8.8.8",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
},
{
"address": "1.1.1.1",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
}
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"domain": [
"goproxy.io",
"amazon.com",
"microsoft.com",
"jd.com",
"youku.com",
"baidu.com"
],
"type": "field",
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"barkinwee.live",
"bestrealprizes.life",
"snapcheat16s.com",
"cloudnetstorage.com",
"hot-dating-here.life",
"glg.spign.nl",
"www.needevery.in",
"next-pops.top",
"1423.barkinwee.live",
"get-my-prize.in",
"achieve-superprizes.life",
"geosite:category-ads-all"
],
"outboundTag": "adblock"
},
{
"type": "field",
"ip": [
"geoip:private",
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "direct"
}
]
}
}
}

v2ray搭配shadowsocks

  • 服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"inbounds": [
{
"port": 2443,
"protocol": "shadowsocks",
"settings": {
"password": "<your-password>",
"method": "chacha20-ietf-poly1305"
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct",
"settings": {}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
]
}
  • 客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
{
"inbounds": [
{
"port": 3080,
"protocol": "socks",
"settings": {
"udp": false
}
}
],
"outbounds": [
{
"protocol": "shadowsocks",
"settings": {
"servers": [
{
"address": "vps6", // 走IPv6
"port": 2443,
"password": "<your-password>",
"method": "chacha20-ietf-poly1305"
},
{
"address": "vps", // 走IPv4
"port": 2443,
"password": "<your-password>",
"method": "chacha20-ietf-poly1305"
}
]
}
},
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "adblock"
}
],
"dns": {
"servers": [
{
"address": "223.5.5.5",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org"
]
},
{
"address": "114.114.114.114",
"port": 53,
"domains": [
"geosite:cn",
"ntp.org"
]
},
{
"address": "8.8.8.8",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
},
{
"address": "1.1.1.1",
"port": 53,
"domains": [
"geosite:geolocation-!cn"
]
}
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"domain": [
"goproxy.io",
"amazon.com",
"microsoft.com",
"jd.com",
"youku.com",
"baidu.com",
"cn.element14.com",
"taobao.com",
"proxy.golang.com.cn"
],
"type": "field",
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"barkinwee.live",
"bestrealprizes.life",
"snapcheat16s.com",
"cloudnetstorage.com",
"hot-dating-here.life",
"glg.spign.nl",
"www.needevery.in",
"next-pops.top",
"1423.barkinwee.live",
"get-my-prize.in",
"achieve-superprizes.life",
"geosite:category-ads-all"
],
"outboundTag": "adblock"
},
{
"type": "field",
"ip": [
"geoip:private",
"geoip:cn"
],
"outboundTag": "direct"
},
{
"type": "field",
"domain": [
"geosite:cn",
"iqiy.com"
],
"outboundTag": "direct"
}
]
}
}
}

  • 使用systemd管理v2ray服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~$ cat /etc/systemd/system/v2ray.service
[Unit]
Description=V2Ray Service
Documentation=https://www.v2fly.org/
After=network.target nss-lookup.target

[Service]
DynamicUser=yes
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ExecStart=/usr/local/bin/v2ray run -config /etc/v2ray/config.json
Restart=on-failure
RestartPreventExitStatus=23

[Install]
WantedBy=multi-user.target

  • 最终可以把两个配置合并成一个配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
~$ cat /etc/v2ray/config.json
{
"inbounds": [
{
"port": 3080,
"protocol": "socks",
"settings": {
"udp": false
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"tag": "rpi",
"port": 1443,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "you-as-server-uuid"
}
]
}
}
],
"outbounds": [
{
"protocol": "vmess",
"settings": {
"vnext": [
{
"port": 1443,
"address": "your-server-domain-or-address",
"users": [
{
"id": "your-remote-server-uuid"
}
]
}
]
},
"streamSettings": {
"network": "http",
"security": "tls",
"tag": "proxy",
"httpSettings": {
"path": "/ray"
},
"tlsSettings": {
"allowInsecure": false
}
}
},
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "adblock"
}
],
"dns": {
"servers": [
[...]
]
},
"routing": {
"strategy": "rules",
"settings": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"inboundTag": [
"rpi"
],
"outboundTag": "vps"
},
[....]
]
}
}
}

  • 使用geoip文件的需要复制到/usr/share/v2ray目录下
1
2
3
~$ ls /usr/share/v2ray/geo*
/usr/share/v2ray/geoip.dat /usr/share/v2ray/geosite.dat

Android手机客户端

  • SagerNet/SagerNet,可以从源码编译,也可以从F-Droid下载。另一个同类型的客户端2dust/v2rayNG,安装后,无法边接到服务器,但是SagerNet是可以的。具体编译安装参照本文的shadowsocks-android.

shadowsocks-libev

  • 编译安装
    1
    2
    3
    4
    5
    6
    7
    8
    ~$ apt-get install  libsodium-dev libmbedtls-dev libev-dev libpcre3-dev libc-ares-dev cmake \
    libbloom-dev libcork-dev libc-ares2 libipset-dev -y
    ~$ git clone https://github.com/shadowsocks/shadowsocks-libev
    ~$ cd shadowsocks-libev/
    ~$ git submodule update --init --recursive
    ~$ cd build/
    ~$ cmake ../
    ~$ make && make install

配置ss-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
~$ sudo mkdir /etc/shadowsocks-libev/
~$ cd /etc/shadowsocks-libev/
~$ sudo cat > config.json < EOF
{
"server": ["::","0.0.0.0"],
"server_port": 8443,
"password": "<password>",
"method": "chacha20-ietf-poly1305",
"timeout":300,
"mode": "tcp_and_udp",
"fast_open": true
}
EOF

~$ ss-server -c /etc/shadowsocks-libev/config.json

配置ss-local

1
2
3
4
5
6
7
8
9
10
{
"server": "<server ip>",
"server_port": 8443,
"local_port": 1088,
"password": "<passwd>",
"method": "chacha20-ietf-poly1305",
"timeout":60,
"fast_open": false,
"mode": "tcp_and_udp"
}
  • 在本地运行一个ss-local -c ./config.json实例,成功连接后,可以使用127.0.0.1:1088的去做Socks5代理了.

SargerNet客户端

1
2
3
4
~$ git clone https://github.com/SagerNet/SagerNet
~$ cd SagerNet
~$ git submodule update --init --recursive
~$ export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true"
  • maybe should set proxy
1
2
3
4
5
6
~$ cat ~/.gradle/gradle.properties
systemProp.http.proxyHost=127.0.0.1
systemProp.http.proxyPort=2080
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=2080

shadsowsocks-android客户端

  • 下载源码并设置编译环境

    1
    2
    3
    4
    5

    ~$ git clone --recurse-submodules https://github.com/shadowsocks/shadowsocks-android
    ~$ cd shadowsocks-android && git submodule update --init --recursive
    ~$ cd core/src/main/rust/shadowsocks-rust
    ~$ rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
  • 这里可以用使用sdkman安装java的开发环境:jdk,gradle. 如果本机支持IPv6连接,可能需要设如下变量:

1
~$ export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true"
  • 还需要安装rust的开发环境。
1
2
3
~$ rustup target add aarch64-linux-android
~$ rustup target add armv7-linux-androideabi
~$ rustup target add x86_64-linux-android
  • 编译错误,如下所示,需要设置:export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true -Dhttps.protocols=TLSv1.2".
1
2
3
4
5
6
7
8
9
10
11
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':buildSrc:compileKotlin'.
> Error while evaluating property 'filteredArgumentsMap' of task ':buildSrc:compileKotlin'
> Could not resolve all files for configuration ':buildSrc:compileClasspath'.
> Could not download kotlin-stdlib-jdk8-1.5.21.jar (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21)
> Could not get resource 'https://jcenter.bintray.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.5.21/kotlin-stdlib-jdk8-1.5.21.jar'.
> Could not HEAD 'https://jcenter.bintray.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.5.21/kotlin-stdlib-jdk8-1.5.21.jar'.
> The server may not support the client's requested TLS protocol versions: (TLSv1.2, TLSv1.3). You may need to configure the client to allow other protocols to be used. See: https://docs.gradle.org/7.2/userguide/build_environment.html#gradle_system_properties

  • rust编译错误,这里只需按提示处理就可以了.运行rustup target add armv7-linux-androideabi后再重新运行编译。
1
2
3
4
5
6
7
8
9
10
   Compiling parking_lot_core v0.9.3
error[E0463]: can't find crate for `core`
|
= note: the `armv7-linux-androideabi` target may not be installed
= help: consider downloading the target with `rustup target add armv7-linux-androideabi`

error[E0463]: can't find crate for `compiler_builtins`

error[E0463]: can't find crate for `core`

  • 编译错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/chacha20-0.8.2/src/lib.rs:82:5
|
82 | feature(stdsimd, aarch64_target_feature)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: the feature `aarch64_target_feature` has been stable since 1.61.0 and no longer requires an attribute to enable

error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/chacha20-0.8.2/src/lib.rs:82:13
|
82 | feature(stdsimd, aarch64_target_feature)
| ^^^^^^^

  • 上面的错误,是因为rust的工具链不匹配造成的。按如下操作使用nightly版本的工具链。
1
2
3
4
5
6
~$ rustup toolchain list
~$ rustup default nightly
~$ rustup update
~$ rustup target add aarch64-linux-android
~$ rustup target add armv7-linux-androideabi
~$ rustup target add x86_64-linux-android
  • 再继续编译工程
1
2
~$ ./gradlew build
~$ ./gradlew assembleRelease

安装apk

  • 生成apk自签名用的key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
~$ keytool -genkey -v -keystore ~/.android/lcy-release.keystore -alias self-build-signed -keyalg RSA -keysize 2048 -validity 10000
Enter keystore password:
Re-enter new password:
What is your first and last name?
[Unknown]:
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
for: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
[Storing /home/michael/.android/lcy-release.keystore]

  • 查看目标手机的CPU架构。
1
2
$ adb shell getprop ro.product.cpu.abi
arm64-v8a
  • 对目标安装文件进行zip压缩对齐
1
2
3
shadowsocks-android$ export PATH=~/Android/Sdk/build-tools/33.0.0:$PATH
shadowsocks-android$ cd mobile/build/outputs/apk/release/
shadowsocks-android$ zipalign -v -p 4 mobile-arm64-v8a-release-unsigned.apk mobile-arm64-v8a-release-unsigned-aligned.apk
  • apk签名
1
shadowsocks-android$ apksigner sign --ks ~/.android/lcy-release.keystore --out shadowsocks-android-master-$(date +%Y-%m-%d)-signed.apk mobile-arm64-v8a-release-unsigned-aligned.apk
  • 安装apk
1
shadowsocks-android/mobile/build/outputs/apk/release$ adb install shadowsocks-android-master-2022-08-28-signed.apk

使用Cloudflare

  • 发现在使用cloudflare有几个前提,1.需要有一个域名,2.网站访问必须支持TLS/HTTPS,而且我这里使用的是Full(strict)模式:Encrypts end-to-end, but requires a trusted CA or Cloudflare Origin CA certificate on the server.域名我是在dynadot上注册的,选了一个15元一年的域名。

  • 先在https://www.cloudflare.com注册一个帐号,在dash -> Websites -> Add a Site,添加刚才注册的域名,如:example.com。进入example.com站点内,查看DNS -> Records -> Cloudflare Nameservers,会为这个example.com域名分配两个域名服务器NS. 再进入到dynadot -> My Domains -> Name Servers删除默认的dynadot提供的NS,添加cloudflare分配的这两个NS链接。

使用Nginx代理v2ray+headscale

  • 先在DNS -> Records -> Cloudflare Nameservers添加两个A 记录, 如:vmss.example.com,headscale.example.com,这里必须这两个主机名申请到证书,如上面用acme.sh去申请。这里原来走了一些弯路使用了cloudflare -> SSL/TLS -> Edge Certificates,导致下面的验证无法成功。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
~$ cat /etc/nginx/sites-enabled/ssl
map $http_upgrade $connection_upgrade {
default keep-alive;
'websocket' upgrade;
'' close;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2 ;

ssl_certificate /etc/v2ray/ssl/fullchain.cer;
ssl_certificate_key /etc/v2ray/ssl/vmss.example.com;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers off;

server_name vmss.example.com;
location / {
proxy_redirect off;
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $server_name;
proxy_redirect http:// https://;
# Show real IP in v2ray access.log
# proxy_set_header X-Real-IP $remote_addr;
proxy_intercept_errors on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

}

server {
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;

ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/headscale.example.com;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
#ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers off;

server_name headscale.example.com;
location / {
proxy_redirect off;
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $server_name;
proxy_redirect http:// https://;
# Show real IP in v2ray access.log
# proxy_set_header X-Real-IP $remote_addr;
proxy_intercept_errors on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

# 这里的headscale-ui就是上面docker-compose.yml的设置。
location /web/ {
proxy_pass https://127.0.0.1:9443/web/;
}

}

  • headscale的配置部署就如上面所述,v2ray的配置是基于ws,没有设置TLS加密,TLS交给Nginx反向代理去处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
~$ cat /etc/v2ray/config.json
{
"log": {
"loglevel": "none"
},
"inbounds": [
{
"port": 10000,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "<your uuid>",
"alterId": 0
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/wss",
"headers": {
"Host": "vmess.exmaple.com"
}
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct",
"settings": {}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "blocked"
}
]
}
}

错误

1
rejected  proxy/vmess/encoding: invalid user > proxy/vmess: Not Found
  • 上面错误,很有可能是有客户端与服务器的时间不对,需要与世界时钟服务器去同步。

URI与二维码

  • quick-guide

  • 在一些移动APP中,为了安全或是方便分享,可以使用二维码来添加服务器.它的最终格式如下:

    1
    ss://YmYtY2ZiOnRlc3QvIUAjOkAxOTIuMTY4LjEwMC4xOjg4ODg#example-server
  • 示例,如有一个服务器是192.168.100.1:8888,使用bf-cfb的加密算法,密码是test/!@#:,它的明文URI是:
    ss://bf-cfb:test/!@#:@192.168.100.1:8888,需要把它编码BASE64格式的URI,下面通过浏览器的Web Console运行:

    1
    2
    > console.log( "ss://" + btoa("bf-cfb:test/!@#:@192.168.100.1:8888") )
    ss://YmYtY2ZiOnRlc3QvIUAjOkAxOTIuMTY4LjEwMC4xOjg4ODg=
  • 现在可以把BASE64URI再编码成二维码,还可以加名字标记如:ss:<BASE64>#<server-name>,quick-guide的后面生成二维的工具,IOS系统中的客户端名字是Outline App,它就是只能通过URI来添加服务器.

配置Systemd服务

  • 这里可以参照上面trojan的系统服务,也可以直接复制shadowsocks-libev/debian/shadowsocks-libev.service到系统目录下.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ~$ sudo cp shadowsocks-libev/debian/shadowsocks-libev.default /etc/default/shadowsocks-libev
    ~$ sudo cat > '/etc/systemd/system/shadowsocks-libev.service' < EOF
    [Unit]
    Description=Shadowsocks-libev Default Server Service
    Documentation=man:shadowsocks-libev(8)
    After=network-online.target

    [Service]
    Type=simple
    CapabilityBoundingSet=CAP_NET_BIND_SERVICE
    AmbientCapabilities=CAP_NET_BIND_SERVICE
    EnvironmentFile=/etc/default/shadowsocks-libev
    User=nobody
    Group=nogroup
    LimitNOFILE=32768
    ExecStart=/usr/local/bin/ss-server -c $CONFFILE $DAEMON_ARGS

    [Install]
    WantedBy=multi-user.target
    EOF

    ~$ sudo systemctl daemon-reload
    ~$ sudo systemctl start shadowsocks-libev

插件部分

使用Docker安装

Dokku安装

  • 这里为什么要用Dokku?本来一个Dockfile直接用Docker就可以,但是关于trojan要用到letscrypt证书的问题,这里还是使用Dokku来完成它.
1
2
~$ wget https://raw.githubusercontent.com/dokku/dokku/v0.21.4/bootstrap.sh;
~$ sudo DOKKU_TAG=v0.21.4 bash bootstrap.sh

安装Brook

  • 它可能是目前最灵活,但同时又保持了较高易用性的架设方法.支持多协议多模式,跨平台也比其它技术好.它是用GO语言写的,这里也是不想从源码编译,直接去下载一个最新使用.下面会是一些使用示例,最完整的还参考它的Wiki,安装(install-cli)参考

  • 服务端

1
~$ ./brook server -l :8118 -p passwd1
  • 客户端
1
~# ./brook client -l 127.0.0.1:4444 -i 127.0.0.1 -s <serverip>:8118 -p passwd1

使用systemd管理

  • 创建如下文件,服务端与客户端类似,如果要在systemd内监听小于1024的端口,需要开启CapabilityBoundingSet=CAP_NET_BIND_SERVICE,AmbientCapabilities=CAP_NET_BIND_SERVICE两项.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    ~$ cat /etc/systemd/system/brook.service
    [Unit]
    Description=Brook service
    Documentation=https://github.com/txthinking/brook
    After=network.target network-online.target nss-lookup.target

    [Service]
    ExecStart=/usr/bin/brook $DAEMON_ARGS
    CapabilityBoundingSet=CAP_NET_BIND_SERVICE
    AmbientCapabilities=CAP_NET_BIND_SERVICE
    Restart=always
    RestartSec=10
    StandardOutput=syslog
    StandardError=syslog
    SyslogIdentifier=brook
    EnvironmentFile=/etc/default/brook
    User=nobody
    Group=nogroup
    LimitNOFILE=500000
    LimitNPROC=500000

    [Install]
    WantedBy=multi-user.target
  • 环境参数文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    ~$ cat>/etc/default/brook<<EOF
    # brook Upstart and SysVinit configuration file

    #
    # THIS FILE DOES NOT APPLY TO SYSTEMD
    #
    # Please see the documentation for "systemd drop-ins":
    # https://docs.docker.com/engine/admin/systemd/
    #


    # Use brook --help to modify the daemon startup options.
    # Extra command line arguments

    DAEMON_ARGS='client -s <your service>:443 --socks5 127.0.0.1:1080 -p <your password>'
    # Enable during startup?
    START=yes


    # User and group to run the server as
    USER=nobody
    GROUP=nogroup

    # Number of maximum file descriptors
    MAXFD=32768
    EOF
1
2
3
~$ sudo systemctl enable brook
~$ sudo systemctl start brook
~$ sudo systemctl status brook

FRP服务

编译源码

1
2
3
4
5
6
7
8
~$ git clone https://github.com/fatedier/frp
~$ cd frp && make
~$ tree bin/
bin/
├── frpc
└── frps

0 directories, 2 files

使用docker运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
FROM golang:1.17 AS builder
RUN go version

ARG upx_version=3.96
ARG GOPROXY

RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.io,direct

COPY . /go/src/github.com/xindalcy/frp
WORKDIR /go/src/github.com/xindalcy/frp
#RUN set -x && \
# go get github.com/golang/dep/cmd/dep && \
# dep ensure -v

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags="-w -s" -o bin/frps ./cmd/frps

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# hadolint ignore=DL3008
RUN apt-get update && apt-get install -y --no-install-recommends xz-utils && \
curl -Ls https://github.com/upx/upx/releases/download/v${upx_version}/upx-${upx_version}-amd64_linux.tar.xz -o - | tar xvJf - -C /tmp && \
cp /tmp/upx-${upx_version}-amd64_linux/upx /usr/local/bin/ && \
chmod +x /usr/local/bin/upx

RUN /usr/local/bin/upx -9 /go/src/github.com/xindalcy/frp/bin/frps

FROM scratch
COPY --from=builder /go/src/github.com/xindalcy/frp/bin/frps /go/bin/frps

EXPOSE 7001/tcp
EXPOSE 7500/tcp
EXPOSE 7001/udp
EXPOSE 7002/udp

VOLUME /etc/frp/

ENTRYPOINT ["/go/bin/frps","-c","/etc/frp/frps.ini"]

服务端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~$ cat /etc/frps.ini
[common]
bind_port = 7001
bind_udp_port = 7002
kcp_bind_port = 7001
authentication_method = token
token = 1122aabbcc # 建议使用 xxd -l 16 -p /dev/random
tcp_mux = true
protocol = kcp # 这
udp_packet_size = 1500

# dashboard 很简单,没有什么可以看的.
dashboard_port = 7500
# dashboard's username and password are both optional
dashboard_user = admin
dashboard_pwd = admin

~$ frps -c /etc/frps.ini

加入Systemed服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
~$ cat /etc/systemd/system/frps.service
[Unit]
Description=frps service
Documentation=https://github.com/fatedier/frp
After=network.target network-online.target nss-lookup.target

[Service]
ExecStart=/usr/bin/frps -c /etc/frps.ini
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=frps
User=nobody
Group=nogroup
LimitNOFILE=500000
LimitNPROC=500000

[Install]
WantedBy=multi-user.target

被控端

P2P Mode

*xtcpis designed for transmitting large amounts of data directly between clients. A frps server is still needed, as P2P here only refers the actual data transmission.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
~$ cat .config/frpc.ini
# frpc.ini
[common]
server_addr = <your server address>
server_port = 7001
token = 1122aabbcc # 与服务器一致.

# 可以使用自签名的证书
# tls_enable = true
# tls_only = true
# tls_cert_file = /etc/frp/tls/client.crt
# tls_key_file = /etc/frp/tls/client.key
# tls_trusted_ca_file = /etc/frp/tls/ca.crt

# 如果是使用kcp协议, server_port必须是服务器指定的kcp_bind_port.
# protocol = kcp
# server_port = 7011



# 本地SSH服务
[build_ssh]
type = xtcp
sk = aabbcc123 # 访问该服务的认证密钥.
local_ip = 127.0.0.1
local_port = 22
# 加密压缩可以选,如果要加,必须两端一致.
use_encryption = true
use_compression = true


#本地spice服务,类似VNC
[osx]
type = xtcp
sk = aabbcc123
local_ip = 127.0.0.1
local_port = 5930

#本地spice服务,类似VNC
[win10]
type = xtcp
sk = aabbcc123
local_ip = 127.0.0.1
local_port = 5940

[zkfd]
type = xtcp
sk = aabbcc123
local_ip = 127.0.0.1
local_port = 5980

  • 运行

    1
    2
    3
    4
    5
    6
    2021/06/04 23:17:52 [I] [service.go:304] [294f53354ddf974b] login to server success, get run id [294f53354ddf974b], server udp port [7002]
    2021/06/04 23:17:52 [I] [proxy_manager.go:144] [294f53354ddf974b] proxy added: [win10 zkfd jenkins build_ssh osx]
    2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [build_ssh] start proxy success
    2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [win10] start proxy success
    2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [zkfd] start proxy success
    2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [osx] start proxy success
  • 或者命令行的方式

    1
    2
    ~$ frpc xtcp --sk aabbcc123 -s <your server address>:7001 --proxy_name osx --uc --ue --local_ip 127.0.0.1 --local_port 5901   -t 1122aabbcc

控制端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
cat .config/frpc.ini
[common]
server_addr = <your server address>
server_port = 7001
token = 1122aabbcc # 与服务器一致.


[p2p_ssh_visitor]
type = xtcp
role = visitor
server_name = secret_ssh
sk = aabbcc123
bind_addr = 127.0.0.1
bind_port = 23222
use_encryption = true
use_compression = true


[build_visitor]
type = xtcp
role = visitor
server_name = build_ssh
sk = aabbcc123
bind_addr = 127.0.0.1
bind_port = 5122

[win10_visitor]
type = xtcp
role = visitor
server_name = win10
sk = aabbcc123
bind_addr = 127.0.0.1
bind_port = 5940

[zkfd_visitor]
type = xtcp
role = visitor
server_name = zkfd
sk = aabbcc123
bind_addr = 127.0.0.1
bind_port = 5980

[osx_visitor]
type = xtcp
role = visitor
server_name = mac
sk = aabbcc123
bind_addr = 127.0.0.1
bind_port = 5930

  • 控制端运行

    1
    2
    3
    4
    5
    6
    7
    8
    2021/06/07 21:30:13 [I] [service.go:304] [b6d7adb82bbcd374] login to server success, get run id [b6d7adb82bbcd374], server udp port [7002]
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
    2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success

  • 命令行运行.

    1
    ~$ frpc xtcp --role visitor --server_name osx --sk aabbcc123 -s <your server address>:7001 --uc --ue --bind_addr 127.0.0.1  --bind_port 6900  -t 1122aabbcc
  • 在本机或者局域网内运行控制端后,就可以通过它去连接的服务器上的服务了.如:连接到p2p_ssh_visitor,直接ssh user@127.0.0.1 -p 23222.
    *frp本身支持直接暴露HTTP web服务,如果只内网的一些私用的web服务,也可以在frp的代理下,再进行一次SSH本地代理转发,下面是通过SSH -L把对端局域内的某一个8080服务转发本地的8080,如:

1
~$ ssh -L 8080:172.17.0.56:8080 user@127.0.0.1 -p 23222 -fNTC

TLS加密通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
~$ cat generate_cs_cert.sh
#!/bin/bash

#
# If you using frp via IP address and not hostname, make sure to set the appropriate IP address in the Subject Alternative Name (SAN) area when generating SSL/TLS Certificates.

ETH0_IPv4=`ip addr show dev eth0 | grep "inet" | head -n1 | awk '{print $2}' | awk -F '/' '{print $1}'`
DOMAIN=`dig -x ${ETH0_IPv4} | grep "PTR" | grep -v '^;' | awk '{print $5}'`

export TLS_DIR=$1
[ ! -d $TLS_DIR ] && mkdir $TLS_DIR && cd $TLS_DIR

cat > my-openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
x509_extensions = usr_cert
[ req ]
default_bits = 2048
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
string_mask = utf8only
prompt = no
[ req_distinguished_name ]
C = US
ST = VA
L = SomeCity
O = MyCompany
OU = MyDivision
CN = ${DOMAIN}
[ req_attributes ]
[ usr_cert ]
basicConstraints = CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
EOF


# build ca certificates

echo "---> build ca certificates"
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${DOMAIN}" -days 5000 -out ca.crt


# build frps server side certificates

echo "---> build frps server side certificates"
openssl genrsa -out server.key 2048

openssl req -new -sha256 -key server.key -out server.csr -config my-openssl.cnf

openssl x509 -req -days 365 \
-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=IP:${ETH0_IPv4}") \
-out server.crt

# build frpc client side certificates

echo "---> build frpc client side certificates"

openssl genrsa -out client.key 2048
openssl req -new -sha256 -key client.key -out client.csr -config my-openssl.cnf

openssl x509 -req -days 365 \
-in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=IP:${ETH0_IPv4}") \
-out client.crt


# verify the server certificate:

openssl verify -CAfile ca.crt server.crt
ca.crt: OK
server.crt: OK

# verify the client certificate:
openssl verify -CAfile ca.crt client.crt
ca.crt: OK
client.crt: OK

测试证书

1
2
3
~$ openssl s_server -cert server.crt -key server.key -accept 1443 -www
Using default temp DH parameters
ACCEPT
  • 可以使用浏览器打开,也可以使用下面命令测试
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    openssl s_client -connect localhost:1443
    CONNECTED(00000003)
    Can't use SSL_get_servername
    depth=0 C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
    0 s:C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
    i:CN = 66.228.37.43
    ---
    [...]

服务端证书配置

1
2
3
4
5
6
7
[common]
tls_enable = true
tls_only = true
tls_cert_file = /etc/frp/tls/server.crt
tls_key_file = /etc/frp/tls/server.key
tls_trusted_ca_file = /etc/frp/tls/ca.crt
[...]

客户端证书配置

1
2
3
4
5
6
7
8
9
10
[common]
server_addr = <your SAN address>

tls_enable = true
tls_cert_file = /etc/frp/tls/client.crt
tls_key_file = /etc/frp/tls/client.key
tls_trusted_ca_file = /etc/frp/tls/ca.crt
[...]

~$ sudo chown nobody:nogroup -R /etc/frp/tls
  • 注意,如果开始TLS后,[common] -> server_addr就必须是证书里的SAN,不要使用/etc/hosts里的映射,否则会报如下:
1
2
3
2021/06/13 23:58:22 [W] [service.go:104] login to server failed: x509: certificate is not valid for any names, but wanted to match xxx
x509: certificate is not valid for any names, but wanted to match xxx

使用Cloudflare Warp原生IP

Install cloudflare-warp Client

  • First, install the repository’s GPG key:

    1
    curl https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
  • Then add the repository to your machine’s apt sources:

1
2
3
4
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list

~$ apt-get update -y
~$ apt-get install cloudlare-warp -y

Configure WARP

  • If you are first install, your need register an account before using it. That register information will store at /var/lib/cloudflare-warp/reg.json.
1
2
~$ wrap-cli register

  • And then set the proxy mode, this step is very important because the default mode is WARP mode, that will bring your whole VPS into the the cloudflare VPN Network,and then you will lose the connection with your VPS.
1
2
~$ warp-cli set-mode proxy
~$ warp-cli enable-always-on
  • After that, you can use wrap-cli settings to view your configuration.You can also check the the configration to determine if it was success configured. configure file store at /var/lib/cloudflare-warp/settings.json.

Connection to WARP and then verify it

1
2
3
4
~$ warp-cli connect
~$ warp-cli status
Status update: Connected
Success
  • When the connection is successful, your system will have a “Socks5” proxy daemon which listens to “127.0.0.1:40000”, you can use the following command to check if WARP is proxied successfully.
1
2
3
4
5
6
7
8
9
10
11
12
~$ curl -x "socks5://127.0.0.1:40000" ipinfo.io
{
"ip": "1x4.28.2x9.x17",
"city": "Atlanta",
"region": "Georgia",
"country": "US",
"loc": "13.7490,-84.3880",
"org": "AS13x35 Cloudflare, Inc.",
"postal": "30302",
"timezone": "America/New_York",
"readme": "https://ipinfo.io/missingauth"
}
  • If you saw the kind of text output like above, it’s indicates that WARP configure right and work fine. However, if you see some of warnings during connection, such as the following WARP warning.
1
2
~$ warp-cli connect
Status update: Unable to connect. Reason: Insufficient system resource: file descriptor
  • You should edit the /lib/systemd/system/warp-svc.service like the following:
1
2
3
[Service]
LimitNOFILE=65535
LimitNOFILESoft=65535

customize v2ray route

  • The following configuration enables some domains or IP addresses to pass through the WARP proxy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
{
...
"outbounds": [
{
"protocol": "freedom",
"tag": "direct",
"settings": {}
},
{
"tag": "warp",
"protocol": "socks",
"settings": {
"servers": [
{
"address": "127.0.0.1",
"ota": false,
"port": 40000,
"level": 1
}
]
},
"streamSettings": {
"network": "tcp"
},
"mux": {
"enabled": false,
"concurrency": -1
}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"rules": [
{
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "blocked"
},
{
"type": "field",
"outboundTag": "warp",
"domain": [
"geosite:netflix",
"geosite:openai",
"ipinfo.io",
"openai.com",
"disneyplus.com",
"bing.com"
]
},
{
"type": "field",
"domain": [
"geosite:cn"
],
"outboundTag": "warp"
},
{
"type": "field",
"ip": [
"geoip:cn"
],
"outboundTag": "warp"
},
{
"type": "field",
"outboundTag": "direct",
"network": "udp,tcp"
}
]
}
}

  • As you can see at above "openai.com","disneyplus.com",... will go through the WARP proxy.

联系作者

概述

  • 本篇基本都是参照TI官网的页面教程去实践学习的.所以一打开SimpleLink™ 以太网 MSP432E401Y MCU LaunchPad™ 开发套件页面,就会看到一个描述,下面很简单明确的指明开始用LaunchPad的步骤:
    • 第 1 步:购买 MSP-EXP432E401Y LaunchPad
    • 第 2 步:下载 MSP432 SDK
    • 第 3 步:完成开箱即用体验并接受 SimpleLink Academy 培训
    • SimpleLink™以太网MSP432E401Y微控制器LaunchPad™开发套件是针对基于SimpleLink™ Arm® Cortex®-M4F的以太网MCU的直观评估平台.以太网 LaunchPad开发套件通过集成以太网MAC和一系列有线通信接口(包括:USB-OTG,CAN,Quad-SPI(QSSI),I2C,SPI,UART以及其他串行协议)将重点放在 MSP432E401Y MCU上.
    • MSP432E4 MCU采用了120MHz Arm Cortex-M4F CPU、1MB 闪存、256kB SRAM和先进的加密加速器,为开发人员提供大量的处理资源,从而实现有线和无线连接栈及处理算法,开发稳健的以太网解决方案.开发人员可利用大量SimpleLink无线MCU BoosterPack™插件模块和SimpleLink软件SDK插件,向应用无缝添加无线连接和云集成,从而构建支持物联网且可互操作的智能工业网关应用.
    • SimpleLink MCU SDK Driver中的代码可以在所有SimpleLink MCU中100%可移植,所以即使需求改变,改用新的SimpleLink MCU也并不意味着必须重新开始.

开箱即用体验

  • 这里的原教程是在TI Resource Explorer里面,它的具体的路径是Software > SimpleLink MSP432E4-SDK-3.30.00.22> SimpleLink Academy-3.30.01.00 > LaunchPad Out of Box Experience > MSP432E401Y LaunchPad Out of Box Experience
  • 这里开箱使用体验是在Exosite loT 云平台进行的,所以要先在该平台上注册一个帐号.但是现在看来,还要付费才可以使用,所以就没有试用了.
  • Pin脚定义图:
    msp432e401y_pinout.png

CC3120 BoosterPack插件模块

-CC3100 & CC3200 UniFlash

  • SimpleLink Academy/Overview的页面里找到了这个CC3120 BoosterPack 开箱体箱示例链接,它的真实在路径是CC3120 BoosterPack Out of Box Experience
  • SimpleLink SDK Wi-Fi Plugin Documentation Overview,这里选择的TIREX的绝对路径是/Software/SimpleLink SDK Plugins/Connectivity/SimpleLinkSDKWiFiPlugin(2.40.00.22)/Examples/Development Tools/MSP432E401Y LaunchPad/Demos/ethernet_wifi_tcp_echo/项目,还具体细分的不同操作系统,不同的工具平台:
    • FreeRTOS
      • CCS Compiler
      • GCC Compiler
      • IAR Compiler
    • TI-RTOS
      • CCS Compiler
      • GCC Compiler
      • IAR Compiler
  • 如果在网页中打开的上述工程,可以使用右角Import导入到CCS Cloud中,如果在桌面版的CCS IDE中的Resource Explorer上述工程可以直接导入到本地的workerspace目录里.
    tre-example-import.png

TI 云工具平台

  • 通过浏览器打开https://dev.ti.com会看到一个左边栏加中间一个九宫的格的工具列表.从上到下,从左到右,依次是Resource Explorer,CCS Cloud,SysConfig,UniFlash,GUI Composer Gallery,BoosterPack Checker,PinMux,E2E Community.CCS Cloud是一个网页版CCS IDE它可以从Resource Explorer导入示例工程,可以查看与编辑代码,但是不可以在线编译生成目标文件.
    msp-432-clount-device-detected.png

  • CCS Cloud
    ![CCS Cloud - default.png](/img/ti/CCS Cloud - default.png)

  • 左侧边栏会提示安装TI CLOUD AGENT会提升使用体验.这里是使用Firefox浏览器,它会在浏览里安装TICloudAgent Bridge插件.如果是使用Google Chrome浏览器会提示无法安装浏览器插件,因为墙的原因.安装完插件还会提示下载安装TI Cloud Agent Application.安装完成Agent之后,刷新页面,侧边栏会提示安装一些必要的设备驱动,用于Device detected.如果它检测到支持的设备在线,会在侧边栏里显示设备的ID号,Serial号,以及相应的Get Started!导航链接,这里的连接MSP-EXP432E401Y会出现对应的GUI Composer Gallery,Resource Expolrer,SimpleLink Acdemy三个链接.

  • 下面是使用在线版的UniFlash.
    ![exp432-E401Y UniFlash.png](/imgs/ti/exp432-E401Y UniFlash.png)

    • 打开Resource Expolrer > /Development/Kits and Boards/MSP432E401Y LaunchPad会有该设备的详细描述,与《用户手册》等官方资料.
    • 打开SimpleLink Acdemy > /Software/SimpleLink MSP432E4 SDK (3.30.00.22)/SimpleLink Academy (3.30.01.00)/Overview会有进入最新的SDK的学院教程页面.

桌面版IDE安装(CCSv9)

安装

ccs920-install.png

安装 SDK

通过使用TI Resource Explorer安装

  • CCSv9首面板里Getting Started页里有Resource Explorer(Examples & Docs),New Proejct, Import Proejct三个快捷链接.这里选择打开Resources Explorer,打开会一直显示Starting TIREX ...,视本机的网速快慢而定,如果偶然打开它了,最好是把自己需要用到的SDK全部下载到本地,防止失联.
    ccs920-resource-expolrer.png

  • 打开可以设置 SDK 的下载路径,如下:
    ccsv9-res-settings.png
    ccs920-tre-plugin-install.png

  • 因为学习一种单片机的最好的方法是查看它官方的文档与SDK的示例,TI的官方文档与SDK示例非常丰富,除了线上的dev.ti.com可以在线查看之外,一般手动下载的SDK压缩包里,除了库文件之外还有文档与工具,这里是学习它最权威的资料.一个典型的SDK目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
~$ simplelink_msp432e4_sdk_3_30_00_22$ tree -L 2
.
├── changelog.html
├── docs
│   ├── Documentation_Overview.html
│   ├── driverlib
│   ├── grlib
│   ├── mbedtls
│   ├── ndk
│   ├── ns
│   ├── simplelink_mcu_sdk
│   ├── tidrivers
│   ├── tiposix
│   ├── tirtos
│   ├── tiutils
│   └── usblib
├── examples
│   ├── nortos
│   └── rtos
├── imports.mak.windows
├── kernel
│   ├── freertos
│   ├── makefile
│   ├── nortos
│   └── tirtos
├── license_simplelink_msp432e4_sdk_3_30_00_22.txt
├── manifest_simplelink_msp432e4_sdk_3_30_00_22.html
├── release_notes_simplelink_msp432e4_sdk_3_30_00_22.html
├── source
│   ├── third_party
│   └── ti
└── tools
├── examples
├── iar
├── image_reformer
└── usblib

手动安装

  • 因为Resource Explorer在国内访问很不稳定,经常打不开,所以打开时可以先把这些文件下载下来,或者打包起来移到其它电脑的新系统里安装.只要在Window > Preferences > Code Composer Studio > Products添加要SDK的路径,就可以把相应的SDK文件安装上来了.

导入官方CCS示例工程

  • 这里使用一个官方Demo来测试一下板子组件是否运行正常,ethernet_wifi_tcp_echo它位于TIREX的目录下/Software/SimpleLink SDK Plugins/Connectivity/SimpleLink SDK WiFi Plugin (2.40.00.22)/Examples/Development Tools/MSP432E401Y LaunchPad/Demos/ethernet_wifi_tcp_echo/,很显然这里还需要安装SimpleLink SDK WiFi Plugin-2.40.00.22版本的SDK我这里选择是FreeRTOS,所以还要指定 FreeRTOS的目录.

设置FreeRTOS目录

  • 如果工程中有用到FreeRTOS的但是又没有指定它的路径,会报下面的错误.
    1
    2
    3
    4
    **** Build Finished ****
    Buildfile generation error occurred..
    Required variable 'FREERTOS_INSTALL_DIR'cannot be resolved or is pointing to a non-existent location.
    See 'Preferences > CCS > Build > Variables' page to define this variable before building this project.
    ccs920-prj-build-var-settings.png

设置工程参数

  • SysConfig
  • Syscfg 配置或查看,应该是属于类似STM32CubeMX的工具,如果使用Syscfg配置,就会根据配置的参数,在工程目录下自动生成Debug/syscfg/{Board.h,Board.c文件,相当于把图行里配置参数自动生成代码,一般SimpleLink SDK的示例工程都会带有Syscfg支持,如果自建工程没有话,可以在工程目录新建一个后缀名为.syscfg的文件,打开工程的Properties > Build > Sysconfig > Summary of falgs set: 加入下面设置:
1
2
# 注意,SDK_DIR 是SDK的根目录绝对路径.
-s "<SDK_DIR>/simplelink_msp432e4_sdk_4_10_00_13/.metadata/product.json" -o "syscfg" --compiler ccs
  • ,IDE识别后,会调用系统内的SysConfg来向导编辑与配置.如果不喜欢此工具,也可以手动生成这样的板子定义文件.
    ccsv9-syscfg.png

  • 导入ethernet_wifi_tcp_echo到本地CCS里后,要详细阅读ethernet_wifi_tcp_echo_MSP_EXP432E401Y_freertos_ccs/README.html文档.下面是按照文档提示,需要修改network_if.h里的SSIDSECURITY_KEY,也就是说要把它配置成可以连接到你周围的WIFI.

  • 这下面是在工程里main_freertos.c添加一段测试FreeRTOS创建多任务的示例.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    const char *pcTextForTask1 = "Task 1 is running\r\n";
    const char *pcTextForTask2 = "Task 2 is running\r\n";
    static void vTaskFunction(void *pvParameters)
    {
    char *pcTaskName;

    pcTaskName = (char*)pvParameters;
    for(;;)
    {
    printf("%s",pcTaskName);
    vTaskDelay(250);
    }
    }

    int main(void)
    {
    /* 此处代码省略 */
    ......
    /* 创建测试任务*/
    xTaskCreate(vTaskFunction,
    "Task 1",
    1000,
    (void*)pcTextForTask1,
    1,
    NULL);
    xTaskCreate(vTaskFunction,
    "Task 2",
    1000,
    (void*)pcTextForTask2,
    1,
    NULL);
    vTaskStartScheduler();
    return (0);
    }

  • 上述修改保存后,接上板子,按F11直接Debug运行,如果无错,就会在 IDE下方的Console窗口看到不断交错输出Task 2 is running,Task 1 is running信息.

  • 再打开另一个终端使用minicom -o -b 115200 -D /dev/ttyACM0打开会看到如下信息:

1
2
3
4
5
[WLAN EVENT] STA Connected to the AP: lcy-y1s-2.4G , BSSID: 20:76:93:0:ac:8
[NETAPP EVENT] IP acquired by the device
WiFi Interface has connected to lcy-y1s-2.4G
WiFi Interface IP Address is 192.168.1.115
WiFi Interface connected and started
  • 按文档提示,用 putty打开一个telnet 连接到192.168.1.115:1000端口.就会显示如下:
    1
    2
    WiFi: Creating thread clientfd = 1
    wifi0: start clientfd = 0x1
  • 在TI驱动程序库中,提供了两种编程模型来支持用户的程序开发:直接寄存器访问(DRA)模型和软件驱动程序(SD)模型.

CC3100BOOST无线WIFI模块

  • 若要对CC31XXBOOST 板进行编程,必须具备CC31XXEMUBOOST板,这里使用USB-to-TTL的板子来代替与它通信.原来看文档以为一定要使用FTDI的芯片,买了一块FT232H进行连接,不知道为什么不稳定,经常No ACK.手上还有一块CP2102的芯片用的很好.CC3100芯片在后续的Uniflash v4不提供支持的,最新支持的版本的是uniflash v3.4.1.00012,同时只支持i386平台,经测试,安装在Debian 7 (i386)能正常使用.
1
2
3
4
5
6
7
8
9
CP2102       CC3100BOOST
TX -> RX
RX <---- TX
GND ----- GND
nHIB # 这里没用控制它,手动按SW3来触发
nRST # 这里没用控制它,手动按SW2来触发

# 这里不使用CP2102来对CC3100BOOST供电,把CC3100BOOST上的J8(1-2)短接,使用USB为模块供电.

Format格式化SPI闪存

  • Serial Flash型号Micron公司的25PX80VP是8Mb容量也就是1M字节.Uniflashv3 先选择Format格式化,下拉选择1M.中间有提示--- please restart the device ---,此时可以按下模块上的SW3或者是SW2按键一秒,按手册上来说,这本应是用一个GPIO来自动触发它的.

查看文件系统

  • Format完成之后,选择List Files System,会在下方的Debug Console里看到类似如下:.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    [07:12:41] INFO: setting break signal
    [07:12:41] INFO: --- please restart the device --- # 要按SW2重启才能继续进行.
    [07:12:43] INFO: connection succeeded
    [07:12:43] INFO: getting storage list
    [07:12:43] INFO: > Executing Operation: Init
    [07:12:43] INFO: reading version info
    [07:12:43] INFO: DEVICE CC3100 ES1.32
    [07:12:43] INFO: reading version info
    [07:12:45] INFO: > Executing Operation: ListFileSystem
    [07:12:45] INFO: extracting file system information...
    [07:12:45] INFO: Serial Flash block size: 4096 bytes
    [07:12:45] INFO: Serial Flash capacity: 256 blocks

    [07:12:45] INFO: file start size fail total size filename
    [07:12:45] INFO: index block [BLKs] safe [BLKs]
    [07:12:45] INFO: ----------------------------------------------------------------------------
    [07:12:45] INFO: N/A 0 5 N/A 5 FATFS
    [07:12:45] INFO:


    [07:12:45] INFO: Flash usage
    [07:12:45] INFO: -------------------------
    [07:12:45] INFO: used space: 5 blocks
    [07:12:45] INFO: free space: 251 blocks
    [07:12:45] INFO: memory hole: [5-255]
    [07:12:45] INFO: > Executing Operation: Disconnect
    [07:12:46] Operation ListFileSystem returned.

uniflashv3-uart-3100.png

烧入Service Pack Programming

  • 这里的Service Pack Programming来自于CC3100SDK,现在最新(后面可能不更新了)SDK版本的1.3.0,ServicePack最新是1.0.1.14-2.12.2.8 ,了解更多信息可以查看SDK内的各种文档说明.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
07:16:07] INFO: --- please restart the device ---
[07:16:09] INFO: connection succeeded
[07:16:09] INFO: getting storage list
[07:16:09] INFO: > Executing Operation: ServicePackProgramming
[07:16:09] INFO: Path to the service pack file: /home/lcy/servicepack_1.0.1.14-2.12.2.8.bin
[07:16:09] INFO: reading version info
[07:16:09] INFO: CC3100Z Device detected.
[07:16:09] INFO: NWP/MAC/PHY Version from Service Pack:
[07:16:09] INFO: NWP version: 0.0.0.0
[07:16:09] INFO: MAC version: 0.0.0.0
[07:16:09] INFO: PHY version: 0.0.0.0
[07:16:09] INFO: reading version info
[07:16:09] INFO: DEVICE CC3100 ES1.32
[07:16:09] INFO: reading version info
[07:16:11] INFO: downloading NWP CODE
[07:16:11] INFO: Erase storage FLASH
[07:16:11] INFO: erase storage succeeded
[07:16:11] INFO: erase storage completed
[07:16:12] INFO: Verifying Data...
[07:16:12] INFO:

Verification OK
[07:16:13] INFO: Downloading file "/sys/servicepack.ucf" with size 38160
[07:16:18] INFO:

New Token is 0x0
[07:16:18] INFO: Download complete
[07:16:18] INFO: > Executing Operation: Disconnect
[07:16:18] Operation ServicePackProgramming returned.

// 再用 List File System 查看文件系统.

[07:22:37] INFO: --- please restart the device ---
[07:22:39] INFO: connection succeeded
[07:22:39] INFO: getting storage list
[07:22:39] INFO: > Executing Operation: Init
[07:22:39] INFO: reading version info
[07:22:39] INFO: DEVICE CC3100 ES1.32
[07:22:39] INFO: reading version info
[07:22:41] INFO: > Executing Operation: ListFileSystem
[07:22:41] INFO: extracting file system information...
[07:22:41] INFO: Serial Flash block size: 4096 bytes
[07:22:41] INFO: Serial Flash capacity: 256 blocks

[07:22:41] INFO: file start size fail total size filename
[07:22:41] INFO: index block [BLKs] safe [BLKs]
[07:22:41] INFO: ----------------------------------------------------------------------------
[07:22:41] INFO: N/A 0 5 N/A 5 FATFS
[07:22:41] INFO: 4 5 66 no 66 /sys/servicepack.ucf
[07:22:41] INFO:


[07:22:41] INFO: Flash usage
[07:22:41] INFO: -------------------------
[07:22:41] INFO: used space: 71 blocks
[07:22:41] INFO: free space: 185 blocks
[07:22:41] INFO: memory hole: [71-255]
[07:22:41] INFO: > Executing Operation: Disconnect
[07:22:41] Operation ListFileSystem returned.

配置CC31xx/CC32xx Config Groups

  • 这是配置模块的功能,功能比较多(Device Role,Station,AP,P2P,Profiles,HTTP Server,DHCP Server,mDNS Client,Smart Config),根据自己用途去配置.这里把设备角色(Device Role)选择成Station模式,勾选上Update.勾选上Update后,再打开主菜单Operation>Program就会烧写一个/sys/mode.cfg文件,
    uniflashv3-uart-3100-DeviceRole.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
[07:32:39] Begin Program operation.
[07:32:40] INFO: > Executing Operation: Connect
[07:32:42] WARNING: flush succeeded
[07:32:42] INFO: setting break signal
[07:32:42] INFO: --- please restart the device ---
[07:32:48] INFO: connection succeeded
[07:32:48] INFO: getting storage list
[07:32:48] INFO: > Executing Operation: Init
[07:32:48] INFO: reading version info
[07:32:48] INFO: DEVICE CC3100 ES1.32
[07:32:48] INFO: reading version info
[07:32:50] INFO: > Executing Operation: Program
[07:32:50] INFO: > File name: /sys/mcuimg.bin, Update: false, Erase: false
[07:32:50] INFO: > File name: /cert/ca.pem, Update: false, Erase: false
[07:32:50] INFO: > File name: /cert/client.pem, Update: false, Erase: false
[07:32:50] INFO: > File name: /cert/private.key, Update: false, Erase: false
[07:32:50] INFO: > File name: /sys/macadd.bin, Update: false, Erase: true
[07:32:50] INFO: > Erase File: /sys/macadd.bin
[07:32:50] INFO: erasing file "/sys/macadd.bin"
[07:32:50] INFO: deleting file "/sys/macadd.bin"
[07:32:50] INFO: erase file completed
[07:32:50] INFO: > File name: /sys/mode.cfg, Update: true, Erase: false
[07:32:50] INFO: > Size of file = 80
[07:32:50] INFO: > Update File: /sys/mode.cfg
[07:32:50] INFO: Downloading file "/sys/mode.cfg" with size 80
[07:32:50] INFO:

New Token is 0x0
[07:32:50] INFO: Download complete
[07:32:50] INFO: Verifying Data...
[07:32:50] INFO: get file
[07:32:50] INFO: Done. Reading 80 bytes
[07:32:50] INFO:

Verification OK
[07:32:51] INFO: > Updated Token value: 0x0
[07:32:51] INFO: > File name: /sys/ipcfg.ini, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/ap.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/devname.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/mdns.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/dhcpsrv.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/httpsrv.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/pref.net, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/smartconfigkeys.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/stacfg.ini, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/p2p.cfg, Update: false, Erase: false
[07:32:51] INFO: > File name: /sys/pmcfg.ini, Update: false, Erase: false
[07:32:51] INFO: > Executing Operation: Disconnect
[07:32:51] Operation Program returned.
// 再次查看
[07:33:07] Begin ListFileSystem operation.
[07:33:08] INFO: > Executing Operation: Connect
[07:33:10] WARNING: flush succeeded
[07:33:10] INFO: setting break signal
[07:33:10] INFO: --- please restart the device ---
[07:33:16] INFO: connection succeeded
[07:33:16] INFO: getting storage list
[07:33:16] INFO: > Executing Operation: Init
[07:33:16] INFO: reading version info
[07:33:16] INFO: DEVICE CC3100 ES1.32
[07:33:16] INFO: reading version info
[07:33:18] INFO: > Executing Operation: ListFileSystem
[07:33:18] INFO: extracting file system information...
[07:33:19] INFO: Serial Flash block size: 4096 bytes
[07:33:19] INFO: Serial Flash capacity: 256 blocks

[07:33:19] INFO: file start size fail total size filename
[07:33:19] INFO: index block [BLKs] safe [BLKs]
[07:33:19] INFO: ----------------------------------------------------------------------------
[07:33:19] INFO: N/A 0 5 N/A 5 FATFS
[07:33:19] INFO: 4 5 66 no 66 /sys/servicepack.ucf
[07:33:19] INFO: 6 71 1 yes 2 /sys/mode.cfg # 多了一个配置文件.
[07:33:19] INFO:


[07:33:19] INFO: Flash usage
[07:33:19] INFO: -------------------------
[07:33:19] INFO: used space: 73 blocks
[07:33:19] INFO: free space: 183 blocks
[07:33:19] INFO: memory hole: [73-255]
[07:33:19] INFO: > Executing Operation: Disconnect
[07:33:19] Operation ListFileSystem returned.

CC3120BOOST无线Wifi模块

  • CC3120 BoosterPack™插件模块(CC3120BOOST)是一块可轻松连接到TI Launchpad套件的电路板(为MSP-EXP432P401R提供的软件示例);从而能够进行快速软件开发.CC3120BOOST可插入到高级仿真BoosterPack(CC31xxEMUBOOST),还可连接到使用SimpleLink Studio仿真MCU的PC.最后,此套件还可通过适配器板连接到除TI Launchpad套件之外的任何低成本,低功耗MCU平台.
  • 根据simplelink_sdk_wifi_plugin_2_40_00_22文档说明,支持IPv4 and IPv6 TCP/IP Stack,但是在实际应用中,发现无法连接到IPv6 Socket,但是可以获取DHCPv6的地址.查看了SDK源码发现了API的分层调用SlNetSock_connect > SlNetIfWifi_connect > sl_Connect,打开源码发现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
~$ cat simplelink_sdk_wifi_plugin_2_40_00_22/source/ti/drivers/net/wifi/sl_socket.h
[....]
/*!
\brief Initiate a connection on a socket

Function connects the socket referred to by the socket
descriptor sd, to the address specified by addr. The addrlen
argument specifies the size of addr. The format of the
address in addr is determined by the address space of the
socket. If it is of type SOCK_DGRAM, this call specifies the
peer with which the socket is to be associated; this address
is that to which datagrams are to be sent, and the only
address from which datagrams are to be received. If the
socket is of type SOCK_STREAM, this call attempts to make a
connection to another socket. The other socket is specified
by address, which is an address in the communications space
of the socket.


\param[in] sd Socket descriptor (handle)
\param[in] addr Specifies the destination addr\n
sockaddr:\n - code for the
address format. On this version
only AF_INET is supported.\n -
socket address, the length
depends on the code format

\param[in] addrlen Contains the size of the structure pointed
to by addr

\return On success, a socket handle.\n
On a non-blocking connect a possible negative value is SL_EALREADY.
On failure, negative value.\n
SL_POOL_IS_EMPTY may be return in case there are no resources in the system
In this case try again later or increase MAX_CONCURRENT_ACTIONS

\sa sl_Socket
\note belongs to \ref client_side
\warning
*/
#if _SL_INCLUDE_FUNC(sl_Connect)
_i16 sl_Connect(_i16 sd,
const SlSockAddr_t *addr,
_i16 addrlen);
#endif
[....]

下载第一个测试工程Network_termial

  • 下面是是使用Code Composer Stduio导入simplelink_sdk_wifi_plugin_2_40_00_22/examples/rtos/MSP_EXP432E401Y/demos/network_terminal,调试运行如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    ~$ sudo minicom -o -b 115200 -D /dev/ttyACM0

    Welcome to minicom 2.7.1

    OPTIONS: I18n
    Compiled on May 6 2018, 08:02:47.
    Port /dev/ttyACM0, 15:41:53

    Press CTRL-A Z for help on special keys

    user:
    ============================================
    Network Terminal Example Ver: 1.0.1.0
    ============================================

    CHIP: 0x30000000
    MAC: 2.0.0.0
    PHY: 2.2.0.6
    NWP: 3.10.0.5
    ROM: 0
    HOST: 3.0.1.46
    MAC address: f0:c7:7f:18:1b:72

    ============================================

    ================================================================================
    Available commands:

    help scan setpolicy wlanconnect
    wlan_ap_start wlan_ap_stop wlandisconnect connected_stations
    ping send recv createfilter
    enablefilter disablefilter deletefilter enablewowlan
    mdnsadvertise mdnsquery radiotool p2pstart
    p2pstop SoftRoamingEnable SoftRoamingDisable AntSelectionEnable
    AntSelectionDisable CoexEnable CoexDisable Countrycode
    clear

    ================================================================================
    user:

  • 如上面所示,通过连接UART会得到shell接口,比如运行:scan -n 20会扫描到周围的AP,wlan_ap_start可以把模块切换成AP模式运行.具体支持的命令详细内容可以查看该工程内的README.html文件.

Uniflash v5

  • CC3120相对于CC3100主要是增加了securitylower power的性能,CC3120R的模块如此,要对CC3X20BOOST板进行编程,必须具备CC31XXEMUBOOST板.它也可以用通过UART接口对它进行ServerPack更新.按照这里CC3120: Only UART Interface between CC3120 and MSP432E401Y指导是可以用MSP432E401Y板载的XDS110去烧写,接线方式如下:
1
2
3
4
5
6
7
LauchPad  XDS110 (J101)            CC3120BOOST
GND -------- GND
3V3 -------- 3V3
5V -------- 5V
TX -------> RX
RX <------- TX
RST -------- nHIB
  • 上述连接方式,成功连接过一次,后面测试时就无法连接成功一直超时,这个还不知道为什么.后面是使用一个CP210x USB-UART去连接的,使用模块上的USB PWR对模块独立供电,模块上的J7(1-2)短接.CP210x与要模块接就只有三线:TX-RX,TX-RX,GND-GND.同时使用UniFlash.desktop打开的图形配置界面,无法指定端口.下面是使用dslite.sh脚本去运行的.

  • 如下图所示,SLImageCreator是用python2写的,并使用PyInstaller把它编译成本的执行文件,从而避免了源码暴露.但是可以使用PyInstaller的工具pyi-archive_viewer把它解压还原回来.下面尝试把它的SLImageCreator内容解压到本地文件SLImageCreator.py.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~$ pyi-archive_viewer ../SLImageCreator
    pos, length, uncompressed, iscompressed, type, name
    [(0, 2410208, 2410208, 0, 'z', 'out00-PYZ.pyz'),
    (2410208, 172, 237, 1, 'm', 'struct'),
    (2410380, 1169, 2788, 1, 'm', 'pyimod01_os_path'),
    (2411549, 3950, 11334, 1, 'm', 'pyimod02_archive'),
    (2415499, 5629, 18438, 1, 'm', 'pyimod03_importers'),
    (2421128, 2453, 6604, 1, 's', 'pyiboot01_bootstrap'),
    (2423581, 437, 923, 1, 's', 'pyi_rth_pkgres'),
    (2424018, 20959, 119615, 1, 's', 'SLImageCreator')]
    ? X
    extract name? SLImageCreator # 选取 SLImageCreator
    to filename? SLImageCreator.py
    ? Ctrl+D # 在当前目录下会有SLImageCreator.py文件.
  • uniflash_5.0.0/simplelink/imagecreator/bin里的libpython2.7.so.1.0是引用系统库,再链接到本目录的.但运行是出现下面的错误.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ti/uniflash_5.0.0/simplelink/imagecreator$ tree bin/
bin/
├── BuildProgrammingImage
├── BuildProgrammingImage.g2
├── Crypto.Cipher._AES.x86_64-linux-gnu.so
├── Crypto.Cipher._DES3.x86_64-linux-gnu.so
├── Crypto.Cipher._DES.x86_64-linux-gnu.so
├── Crypto.Hash._SHA256.x86_64-linux-gnu.so
├── Crypto.Util._counter.x86_64-linux-gnu.so
├── Crypto.Util.strxor.x86_64-linux-gnu.so
├── libftd2xx.so
├── libpython2.7.so.1.0 > /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
├── libusb-1.0.so
├── SLImageCreator
└── xds110reset

0 directories, 13 files

~$ uniflash_5.0.0/simplelink/imagecreator/bin$ ./SLImageCreator
[....]
ImportError: cannot import name RAND_egd
SLImageCreator returned -1
  • 获取信息,下面的命令参考来自swru469g.pdf文档.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    uniflash_5.0.0$ ./dslite.sh --mode cc31xx device info --json --port /dev/ttyUSB0
    Executing the following command:
    > ./SLImageCreator device info --json --port /dev/ttyUSB0

    For more details and examples, please refer to the UniFlash Quick Start guide.

    Config file (cfg.json) doesn't exist, using defaults
    INFO:root:COM PORT /dev/ttyUSB0
    INFO:slbootloader.slbootloader:Connecting to device
    INFO:slbootloader.slbootloader:--- Please power off the device ---
    Press ENTER to continue
    INFO:slbootloader.slbootloader:Power off
    INFO:slbootloader.slbootloader:Set break signal
    INFO:slbootloader.slbootloader:--- Please power on the device ---
    INFO:slbootloader.slbootloader:Power on
    INFO:slbootloader.slbootloader:Clear break signal
    INFO:slbootloader.slbootloader:Connection succeeded
    INFO:slbootloader.slbootloader:Received storage list
    {
    "mac_address": "f0:c7:7f:18:1b:72",
    "hw_ver": 48,
    "secure": true,
    "device_type": "CC3120",
    "prog_mac_address": null
    }

GUI图形配置

1
uniflash_5.0.0$ ./dslite.sh --mode cc31xx gui_cfg --port /dev/ttyUSB0
  • 成功后转为后台进程,并用系统默认的浏览器打开一个网页,如下:
    uniflash-msp432e4-cc3120r-selected.png
  • 创建一个工程文件,如下:
    uniflash-msp432e4-cc3120r-new-project.png
  • 连接模块,注意:点击connect后,要手动按一下模块上的SW3或SW2复位它,才能连接到.
    uniflashv5-cc3120r-connect.png

Simple配置

  • 如图所示,这Uniflash v5Uniflash v3的界面有很大不同,这个界面只有两个选项Start Role (Station,P2P,Access Point)Service Pack File Name,
    这里的Service Pack File Name文件来自于simplelink_sdk_wifi_plugin_2_40_00_22/tools/cc31xx_tools/servicepack-cc3x20/sp_3.10.0.5_2.0.0.0_2.2.0.6.bin,关于Service Pack内容详情,可以查看SDK内的文档.

Anvanced配置

Genernal
  • 注意,工程类型选成Development模式是不能随意更改MAC Address的,会报错SL_ERROR_FS_DEVELOPMENT_BOARD_WRONG_MAC.
System Setting
Files
  • 使用Online User Files查看模块内的文件系统内容,如下:
    uniflashv5-cc3120r-online-user-files.png

SysConfig

简介

  • SysConfig是一个为了帮助简单配置与加快软件开发图形工具.它是基于node.js平台开发,数据定义结构是基于JSON格式.STM32旗下对应类似工具叫STM32CubeMX.

配置

  • 它是一个独立工具安装包,可以把它安装在$CCS_ROOT/ccs/utils/下面.也可以安装到其它位置,创建一个链接到$CCS_ROOT/ccs/utils/sysconfCCS IDE调用,工程根目录下的.syscfg类型的文件会调用sysconfigCCS IDE打开编辑,如果文件缺少必要的定义或者格式错误,SysConfig会报错,并向导用户新建一个可用的配置.编译时,会先调用$CCS_ROOT/ccs/utils/sysconfig/sysconfig_cli.sh"解析.syscfg内容,会在(Debug|Release)目录创建syscfg目录,会自动的生成ti_drivers_config.c,ti_drivers_config.h,ti_net_config.c这些个文件.它的图形编辑界面如下:
    sysconfig_msp432e401y.png

  • 使用文本编辑器打开工程中的.syscfg格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    cat mqttclient_wifi.syscfg
    /**
    * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
    * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
    * @cliArgs --board "/ti/boards/MSP_EXP432E401Y" --product "simplelink_msp432e4_sdk@4.20.00.12"
    * @versions {"data":"2020021217","timestamp":"2020021217","tool":"1.4.0+1234","templates":"2020021217"}
    */
    const CC3120BOOST = scripting.addHardware("/ti/boards/boosterpacks/CC3120BOOST", "boosterpack2");

    /**
    * Import the modules used in this configuration.
    */
    const Display = scripting.addModule("/ti/display/Display", {}, false);
    const Display1 = Display.addInstance();
    const GPIO = scripting.addModule("/ti/drivers/GPIO");
    [...省略多行..]
    const SlNet = scripting.addModule("/ti/net/SlNet", {}, false);
    const SlNet1 = SlNet.addInstance();

    /**
    * Write custom configuration values to the imported modules.
    */
    Display1.$hardware = system.deviceData.board.components.XDS110UART;
    Display1.$name = "UART0";
    Display1.uart.$name = "MSP_EXP432E401Y_UART0";
    Display1.uart.uart.$name = "MyUART1";

    GPIO3.$name = "MSP_EXP432E401Y_SDSPI_CS";
    GPIO3.mode = "Output";
    GPIO3.outputStrength = "High";
    GPIO3.initialOutputState = "High";
    GPIO3.gpioPin.$assign = "boosterpack.8";

    GPIO4.$hardware = CC3120BOOST.components.CS;
    GPIO4.$name = "MSP_EXP432E401Y_CS_pin";
    GPIO4.initialOutputState = "High";
    GPIO4.outputStrength = "High";

    I2C1.$name = "MSP_EXP432E401Y_I2C2";
    I2C1.i2c.$name = "MyI2C1";
    I2C1.i2c.$assign = "I2C2";
    I2C1.i2c.sdaPin.$assign = "boosterpack2.10";
    I2C1.i2c.sclPin.$assign = "boosterpack2.9";

    [....省略多行...]

  • 在最新工具版本中(1.4以上),.syscfg文件中必须要有@cliArgs --board "/ti/boards/MSP_EXP432E401Y",就是说必须要指定一个可用的--board参数,否则会无法打开并编辑它.再来看一下文件中的@cliArgs --board "/ti/boards/MSP_EXP432E401Y" --product "simplelink_msp432e4_sdk@4.20.00.12"这一行,它其实定义了这个Sysconfig文件的类型定义的来源及解析方式.simplelink_msp432e4_sdk@4.20.00.12是对应工程引用的SDK的版本,打开SDK的源码路径如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 注意SDK名与版本号.
~$ tree -L 2 simplelink_msp432e4_sdk_4_20_00_12/source/ti/boards/.meta
simplelink_msp432e4_sdk_4_20_00_12/source/ti/boards/.meta
├── boosterpacks
│   ├── BOOSTXL-BASSENSORS.syscfg.json
│   ├── BOOSTXL-SHARP128.syscfg.json
│   ├── BP-BASSENSORSMKII.syscfg.json
│   ├── CC3200AUDBOOST.syscfg.json
│   ├── LPSTK-SENSORS.syscfg.json
│   └── MSP430BOOST-SHARP96.syscfg.json
├── components
│   ├── analogInput.json
│   ├── button.json
│   ├── digitalInput.json
│   ├── digitalOutput.json
│   ├── i2c.json
│   ├── led_dimmable.json
│   ├── led.json
│   ├── spi25xFlash.json
│   ├── spiBus.json
│   ├── spiSelect.json
│   ├── uart.json
│   ├── usb.json
│   └── xds110Uart.json
├── MSP432E411Y_BGAEVM.syscfg.json
└── MSP_EXP432E401Y.syscfg.json

2 directories, 21 files

  • 如上所示,SysConfig工具定义的出厂资源描述文件是位于$SDK/source/ti/boards/.meta下,而且它是有分层定义设计的,MSP_EXP432E401Y.syscfg.json是板子定义.components是一些外设模块的定义.boosterpacks是一些可扩展组件的定义,它定义管脚与规格是支持MSP_EXP432E401Y扩展的.

自定义资源文件

  • 下面是参照了官方源码,在boosterpacks中定义了CC3120BOOST.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    cat boosterpacks/CC3120BOOST.syscfg.json

    /*
    * ======== CC3120BOOST.syscfg.json ========
    * 这里是对照MSP-EXP432E401Y Rev 1.0 BoosterPack II 管脚定义的. 对照 SWRU457A PDF文档
    * CC3120 SimpleLinkTM Wi-Fi ® BoosterPackTM Plug-InModule and IoT Solution
    * 排针顺序查看官方 MSP_EXP432E401Y_CC3120BOOST.syscfg.json里的BoosterPack Standard Header #2 部分
    */
    {
    "name": "CC3120BOOST",
    "displayName": "CC3120BOOST",
    "description": "CC3120BOOST Wifi BoosterPack II",
    "longDescription": "The [__CC3120BOOST__](https://www.ti.com/tool/CC3120BOOST) BoosterPack&trade; SimpleLink™ Wi-Fi® CC3120 wireless network processor BoosterPack™ plug-in module ",
    "headerType": "BoosterPack 40 pin",
    "components": {
    "CC3120BOOST_SPI": {
    "displayName": "CC3120BOOST SPI Bus",
    "description": "CC3120BOOST SPI bus",
    "longDescription": "CC3120BOOST SPI bus",
    "type": "SPI_BUS",
    "signals" : {
    /* PQ0: BoosterPack standard: SPI CLK */
    "SCLK" : {"type": "SPI_SCLK", "connection" : 7},
    /* PQ1: BoosterPack standard: SPI FSS */
    "SS" : {"type": "SPI_SS", "connection" : 12},
    /* PQ2: BoosterPack standard: SPI MOSI */
    "MOSI" : {"type": "SPI_MOSI", "connection" : 15},
    /* PQ3: BoosterPack standard: SPI MISO */
    "MISO" : {"type": "SPI_MISO", "connection" : 14}
    }
    },
    "CC3120BOOST_UART": {
    "definition": "/ti/boards/components/uart.json",
    "connections": {
    "RXD": 4, /* PP1 */
    "TXD": 3 /* PP0 */
    }
    },
    "IRQ": {
    "displayName": "IRQ",
    /* "definition": "/ti/boards/components/digitalInput.json",*/
    /* PM7 这里要注手册说明这里是OUT,对应于MSP432E401Y的管脚就是IN,所以这里是INPUT,下同. */
    "signals": {
    "INTERRUPT": {
    "type": "DIN",
    "settings": {
    "pull": "None"
    },
    "connection": 19
    }
    }
    },
    "CS": {
    "displayName": "CS",
    "definition": "/ti/boards/components/digitalOutput.json",
    /* PP5 */
    "connections": { "OUTPUT" : 18 }
    },
    "nHIB": {
    "displayName": "nHIB",
    "description": "nHIB power pin",
    "longDescription": "nHIB power pin",
    "definition": "/ti/boards/components/digitalOutput.json",
    /* *RX */
    "connections": { "OUTPUT" : 5 }
    },
    "nRESET": {
    "displayName": "nRESET",
    "definition": "/ti/boards/components/digitalOutput.json",
    /* RST */
    "connections": { "OUTPUT" : 16 }
    },
    "NWP_LOG_TX": {
    "displayName": "NWP_LOG_TX",
    "definition": "/ti/boards/components/digitalInput.json",
    /* PH0 */
    "connections": { "INPUT" : 34 },
    "settings": {
    "DIN": {
    "pull": "Pull Up",
    "interruptTrigger": "Raising Edge"
    }
    }
    },
    "WLAN_LOG_TX": {
    "displayName": "WLAN_LOG_TX",
    "definition": "/ti/boards/components/digitalInput.json",
    /* PH1 */
    "connections": { "INPUT" : 33 },
    "settings": {
    "DIN": {
    "pull": "Pull Up",
    "interruptTrigger": "Raising Edge"
    }
    }
    }
    }
    }
  • 在工程目录内的.syscfg文件里加上const CC3120BOOST = scripting.addHardware("/ti/boards/boosterpacks/CC3120BOOST","boosterpack2");这一行,打开SysConfig编辑界面如下:
    sysconfig_cc3120boost

  • 如上图所示,这里还自定义一个板子的定义,就是在/ti/boards/MSP_EXP432E401Y基础上删除了MICROUSB定义,命名为/ti/boards/MSP_EXP432E401Y_WITHOUT_USB,但是自定义的CC3120BOOST文件还是不能添加nRESET,nHIB这两个管脚,还是与板子的定义有冲突,这也可能是为什么官方不出一个boosterpacks/CC3120BOOST的组件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"MICROUSB": {
"displayName": "USB Micro Connector",
"description": "USB Micro-A / -B Connector",
"definition": "/ti/boards/components/usb.json",
"connections": {
"DM": "93", /* PL7 */
"DP": "94", /* PL6 */
"ID": "95", /* PB0 */
"VBUS": "96", /* PB1 */
"EPEN": "127", /* PD6 */
"PFLT": "128", /* PD7 */
"CLK": "92", /* PB3 */
"D0": "81", /* PL0 */
"D1": "82", /* PL1 */
"D2": "83", /* PL2 */
"D3": "84", /* PL3 */
"D4": "85", /* PL4 */
"D5": "86", /* PL5 */
"D6": "106", /* PP5 */
"D7": "105", /* PP4 */
"DIR": "104", /* PP3 */
"NXT": "103", /* PP2 */
"STP": "91" /* PB2 */
}
}

CC2650 Module BoosterPack蓝牙模块

烧写蓝牙固件

  • Windows端可以使用SmartRF FlashProgrammer2来烧写,但是需要一根标准JTAG线,且要把MSP432E4 LaunchPad上的J101跳线TDI,TDO,TCK,TMS,RST去掉,只留GND,3V3这两根跳线,使用标准的10pin JTAG线从J102连接XDS-110 JTAG调试信号,具体操作如下图所示.
    msp432e4-smartrf-fp.jpg
    srf-fp2.jpg
  • Linux端使用UniFlash命令行来烧写,UniFlash本身是一个GUI烧写的工具,在选择目标设备有两种:On-chip是透过JTAG烧写,Serial是通过serial bootloader烧写.但是我在实际中用On-Chip烧写失败,用命令行烧写是显示成功的.接线与跳线部分还是上图那样,先要用UniFlash生成一个ccxml配置文件,具体如下图,点击Start后,按上方的download.ccxml保存到文件夹内.
    uniflash-msp432e4-cc2650f128.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
./dslite.sh -c ~/CC2650F128.ccxml --list-device-cmds
Executing the following command:
> /fulllpath/uniflash_5.0.0/deskdb/content/TICloudAgent/linux/ccs_base/DebugServer/bin/DSLite flash
-c ~/CC2650F128.ccxml --list-device-cmds

For more details and examples, please refer to the UniFlash Quick Start guide.

Cortex_M3_0: GEL Output: Memory Map Initialization Complete.
Cortex_M3_0: GEL Output:
-------------------------------------------------
COMMAND DESCRIPTION
PinReset Reset CC13xx/CC26xx device using reset pin.
MassErase Erase flash using mass erase (cannot be combined with
other operations). If the device debug interface is
locked, a target configuration file (.ccxml) with
argument custom="no" must be used.
-------------------------------------------------


./dslite.sh -c ~/CC2650F128.ccxml --post-flash-device-cmd PinReset -e -v
-f /fullpath/simplelink_sdk_ble_plugin_3_20_00_24/source/ti/snp/cc2650/simple_np_cc2650bp_uart_pm_sbl_2_02_01_18a_merge.hex
Executing the following command:
> /fullpath/uniflash_5.0.0/deskdb/content/TICloudAgent/linux/ccs_base/DebugServer/bin/DSLite flash -c ~/CC2650F128.ccxml
--post-flash-device-cmd PinReset -e -f
-v /fullpath/simplelink_sdk_ble_plugin_3_20_00_24/source/ti/snp/cc2650/simple_np_cc2650bp_uart_pm_sbl_2_02_01_18a_merge.hex

For more details and examples, please refer to the UniFlash Quick Start guide.

DSLite version 9.1.0.1655
Configuring Debugger (may take a few minutes on first launch)...
Initializing Register Database...
Initializing: IcePick_C
Executing Startup Scripts: IcePick_C
Initializing: CS_DAP_0
Executing Startup Scripts: CS_DAP_0
Initializing: Cortex_M3_0
Executing Startup Scripts: Cortex_M3_0
[.....]
sorting and removing duplicate symbols: 100%
Cortex_M3_0: GEL Output: Doing Pin Reset ...
  • 参数解释,具体更详细的参数说明,dslite.sh --help.
    • -c 指定ccxml配置文件的位置.
    • -e 详细显示模式
    • -f 烧写文件,这个固件文件可以在simplelink_sdk_ble_plugin_3_20_00_24官方的SDK里面.
    • -v 烧写完成后,校验烧写文件.

单片机入门

  • 时钟周期
    • 时钟周期也称为振荡周期,定义为时钟脉冲的倒数(时钟周期就是单片机外接晶振的倒数,例如12M的晶振,它的时间周期就是1/12us),是计算机中最基本的、最小的时间单位,也称节拍脉冲或T周期.在一个时钟周期内,CPU仅完成一个最基本的动作.对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us;1秒(s)等于1000毫秒(ms),等于1000000微秒(us).
    • 1秒(s) = 1000毫秒(ms)
      1毫秒(ms) = 1000微秒(us)
      1微秒(us) = 1000纳秒(ns)
      1纳秒(ns) = 1000皮秒(ps)
    • 在8051单片机中把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示).
  • 机器周期
    • 在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶段,每一阶段完成一项工作.例如:取指令、读存储器、写存储器等,这每一项工作称为一个基本操作.完成一个基本操作所需要的时间称为机器周期.一般情况下,一个机器周期由若干个S周期(状态周期)组成.8051系列单片机的一个机器周期同6个S周期(状态周期)组成.前面已经说过一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示),8051单片机的机器周期由6个状态周期组成,也就是说一个机器周期=6个状态周期=12个时钟周期.
  • 指令周期
    • 指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成.指令不同,所需的机器周期数也不同.对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期.对于一些比较复杂的指令,例如:转移指令、乘法指令,则需要两个或者两个以上的机器周期.

字节顺序

  • 对于单一的字节(a byte),大部分处理器以相同的顺序处理位元(bit),因此单字节的存放方法和传输方式一般相同.

位序

  • 对于多字节数据,如整数(32位机中一般占4字节),在不同的处理器的存放方式主要有两种,以内存中0x0A0B0C0D的存放方式为例,分别有以下几种方式

  • 大端(Big-Endian)

    • 高位字节存储在低位内存地址,低位字节存储在高位内存地址
    • 如:地址方向是左低右高,数据以8bit为单位时:0x0A0B0C0D ,数据以16bit为单位时:0x0A0B0C0D
    • 网络传输一般采用大端序,也被称之为网络字节序,或网络序.IP协议中定义大端序为网络字节序.
    • 先传高位(MSB)的串行协议:
      • I2C
      • SPI
      • 摩尔斯电码
  • 小端(Little-Endian)

    • 低位字节存储在低位内存地址,高位字节存储在高位内存地址.
    • 如:地址方向是左低右高,数据以8bit为单位时:0x0D0C0B0A ,数据以16bit为单位时:0x0C0D0A0B.
    • 先传低位(LSB)的串行协议:
      • RS-232
      • RS-422
      • RS-485
      • USB
      • 以太网(虽然高字节先传,但每一字节内低位先传)
  • 最高有效位MSB(the most significant bit)

    • 指多字节序列中具有最大权重的字节.在大端序中,msb即指最左端的位.对于有符号二进制数,负数采用反码或补码形式,此时msb用来表示符号,msb为1表示负数,0表示正数.
  • 最低有效位LSB(the least significant bit)

    • 指多字节序列中最小权重的字节,是指一个二进制数字中的第0位(即最低位),权值为2^0,可以用它来检测数的奇偶性.与之相反的称之为最高有效位.在大端序中,lsb指最右边的位.
  • 不同编码的字节顺序标

  • 编码 表标(16进制)
    UTF-16(大端序) FE FF
    UTF-16(小端序) FF FE
    UTF-32(大端序) 00 00 FE FF
    UTF-32(小端序) FF FE 00 00

安装自己的Mosquitto服务器

  • 开启简单用户认证
    1
    2
    3
    4
    5
    // 创建文件,并添加一个用户.
    ~$ sudo mosquitto_passwd -c /etc/mosquitto/passwd sammy
    // 添加一个用户
    ~$ sudo mosquitto_passwd /etc/mosquitto/passwd user2

发行版安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
~$ sudo apt-get install mosquitto -y
~$ sudo cat > /etc/mosquitto/conf.d/default.conf<<EOF
autosave_interval 1800
persistence_file m2.db
connection_messages true
log_timestamp true

listener 1883
protocol mqtt

listener 8883
# protocol mqtt
# cafile /etc/mosquitto/certs/ca.crt
# keyfile /etc/mosquitto/certs/privkey.pem
# certfile /etc/mosquitto/certs/fullchain.pem

allow_anonymous false
password_file /etc/mosquitto/passwd
EOF
  • 配置websockets,需要用的证书文件.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~# ln -svf /etc/letsencrypt/live/<domain>/privkey.pem  /etc/mosquitto/certs/privkey.pem
~# ln -svf /etc/letsencrypt/live/<domain>/fullchain.pem /etc/mosquitto/certs/fullchain.pem
~$ sudo cat > /etc/mosquitto/conf.d/websockets.conf<<EOF
listener 8080
protocol websockets

listener 8083
protocol websockets
# cafile /etc/mosquitto/certs/ca.crt
keyfile /etc/mosquitto/certs/privkey.pem
certfile /etc/mosquitto/certs/fullchain.pem
websockets_log_level 3
EOF

~$ ufw allow 8080/tcp
~$ ufw allow 8883/tcp
~$ systemctl restart mosquitto
mosquitto -c /etc/mosquitto/mosquitto.conf -v

客户端测试

1
~$ mosquitto_sub -h 192.168.1.178 -u test -P test123 -t /lcy/cc3120/sw2
1
~$ mosquitto_pub -h 192.168.1.178 -u test -P test123 -t /lcy/cc3120/sw2 -m 0

源码安装

  • 如果要尝试新功能,可以如下操作.
    1
    2
    3
    4
    5
    6
    ~$ apt-get install cmake libwebsockets-dev libwebsockets8 libc-ares-dev uthash-dev -y
    ~$ git clone https://github.com/eclipse/mosquitto
    ~$ mkdir -pv mosquitto/build && cd mosquitto/build
    ~$ cmake -DWITH_SRV=yes -DWITH_WEBSOCKETS=yes -DWITH_THREADING=yes -DWITH_TLS=yes -DWITH_DOCS=no ../
    ~$ make WITH_SRV=yes WITH_WEBSOCKETS=yes WITH_TLS=yes WITH_DOCS=no -j4
    ~$ make install/local

调试程序跑飞的原因

  • Saving program counter in Fault ISR

  • Debugging Hard Fault & Other Exceptions

  • Diagnosing Software Faults

  • MSP432E401Y SimpleLink™ User Guide.pdf

  • How to debug a HardFault on an ARM Cortex-M MCU

  • A Practical guide to ARM Cortex-M Exception Handling

  • 在开发嵌入式系统程序时,会碰到各种无理头的问题,最严重是它跑飞了,直接进了faultISR(void)里去while.不知道是那里出错了,首先在faultISR(void)函数开始处下一个断点,这里是通过目标map文件找到该文件的指针地址,进入到工程编译成后的Debug内,打开xxx.map,文本搜寻faultISR, 如下图所示,faultISR.text段内的0x00041724的位置.
    ccsv9_map_search_faultISR.png

  • CCS IDE的调试状态下,打开CCS Debug > Disassembly,输入0x00041724搜索,设置断点.再重新运行一次调试.
    ccsv9_debug_registers_disasmbly.png

  • 此时程序跑飞后停在了faultISR(void)处,再根据系统内在各种寄存器来定位出错的位置.
    ccsv9_debug_registers_core.png

  • 如上图所示,在CCS Debug > Registers > Core Registers内会看到PC,SP,LR三个寄存器名,关于寄存器的技术细节一定要参照《Cortex M3与M4权威指南》这本手册书去理解,还有MSP432E401Y SimpleLink™ User Guide.pdf的手册.这里如果显示LRvalue是一个非法无效的值如: 0xFFFFFFFE,就参考SP的值,把SP内的值输入到CCS Debug > Memory Browser内.
    ccsv9_debug_memory_browser.png

  • 如上图所示,从0x2003FFE0开始每4个字节对应一个寄存器,它们依次是R0,R1,R2,R3,R12,LR,PC,XPSR,先用工具链内的objdump把目标烧写文件反汇编到一个文本文件:

1
~$ ./ccs920/ccs/tools/compiler/ti-cgt-arm_18.12.6.LTS/bin/arm-none-eabi-objdump -d  xxxxxx.out  > ~/mps432-debug.txt
  • 如上图所示,按顺序查看到LR的值是0x00031A01,打开msp432-debug.txt,查找31a00,就会找到对应出错的函数位置.
EXC_RETURN Value Mode to Return To Stack to use
0xFFFFFFF1 Handler Mode MSP
0xFFFFFFF9 Thread Mode MSP
0xFFFFFFFD Thread Mode PSP
0xFFFFFFE1 Handler Mode (FPU Extended Frame) MSP
0xFFFFFFE9 Thread Mode (FPU Extended Frame) MSP
0xFFFFFFED Thread Mode (FPU Extended Frame) PSP

调试Bus Fault

ccsv9_debug_registers_nvic_fault_addr.png

  • 当中断在faultISR时,查看到NVIC里的寄存器的值如上图所示,这里NVIC Fault Status (NVIC_FAULT_STAT)的值是0x00008200这里代表它是一个Usage Fault,再展开显示详情Divide-by-Zero Usage Fault.,参考来源《Cortex M3与M4权威指南》第七章,7.4 “优先级定义”,表7.5, 还有参考MSP432E401Y SimpleLink™ User Guide.pdf,1.5小节《内存模型》表1-15 Memory Map.
  • 在这里NVIC Fault Address (NVIC_FAULT_ADDR)的值显示是0x2004.0014,参考表1-15 Memory Map它出错是在SRAM里.假如是:0x4003.100C表示出错在Timer1这个硬件地址,是一个Bus Fault,它的出错主要原因的:程序去访问了没有使能的外设,需要先使能,再访问.
  • objectdump出错.
    1
    2
    ~$ ./ccs920/ccs/tools/compiler/ti-cgt-arm_18.12.6.LTS/bin/arm-none-eabi-objdump --help
    arm-none-eabi-objdump: loadlocale.c:129: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed.
  • 设置LANG环境变量.export LANG=/usr/lib/locale/en_US,再次运行正常.

Energia

  • Installing the LaunchPad drivers
  • Energia是一个开源和社区驱动型集成开发环境(IDE)与软件框架与Arduino的设计理念是一样的.Energia基于接线框架,为微控
    制器编程提供了直观的编码环境和由易于使用的功能API及库构成的可靠框架.Energia支持多种 TI 处理器,主要包括可从LaunchPad开发生态系统获得的处理
    器.Energia是开源产品,源代码可从github获得.
  • 总体来说,Energia是从Arduino分支出来,但是支持的库不是很多,而且最新的版本是2019出的,后续版本好像没有看到.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~$ cat /etc/udev/rules.d/71-ti-permissions.rules
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0403",ATTRS{idProduct}=="a6d0",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0403",ATTRS{idProduct}=="a6d1",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0403",ATTRS{idProduct}=="6010",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="1cbe",ATTRS{idProduct}=="00fd",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="1cbe",ATTRS{idProduct}=="00ff",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0451",ATTRS{idProduct}=="bef1",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0451",ATTRS{idProduct}=="bef2",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0451",ATTRS{idProduct}=="bef3",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0451",ATTRS{idProduct}=="bef4",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0451",ATTRS{idProduct}=="f432",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="0d28",ATTRS{idProduct}=="0204",MODE:="0666"
KERNEL=="hidraw*",ATTRS{busnum}=="*",ATTRS{idVendor}=="0d28",ATTRS{idProduct}=="0204",MODE:="0666"
ATTRS{idVendor}=="0451",ATTRS{idProduct}=="bef0",ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="0c55",ATTRS{idProduct}=="0220",ENV{ID_MM_DEVICE_IGNORE}="1"
KERNEL=="ttyACM[0-9]*",MODE:="0666"

SUBSYSTEM=="usb", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0660", GROUP="dialout", RUN+="/sbin/modprobe ftdi-sio" RUN+="/bin/sh -c '/bin/echo 0451 c32a > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'"

谢谢支持

STM32CubeMX

  • STM32CubeMX这个页面里的Tools&Software包含开发工具与嵌入式工具两大部分.
    ![STM32CubeMX -devtools.png](/imgs/stmcubemx/STM32CubeMX -devtools.png)
    ![STM32CubeMX -Embedded.png](/imgs/stmcubemx/STM32CubeMX -Embedded.png)
    ![STM32CubeMX -Embedded.png](/imgs/stmcubemx/STM32CubeMX -Embedded1.png)
    ![STM32CubeMX -Embedded.png](/imgs/stmcubemx/STM32CubeMX -Embedded2.png)

开发工具

STM32CubeIDE

  • STM32CubeIDE是的ST的官方IDE工具,下载后会得到一个很大zip包,解压后会有SetupSTM32CubeMX-5.4.0.app,SetupSTM32CubeMX-5.4.0.exe,SetupSTM32CubeMX-5.4.0.linux三个项目,其中SetupSTM32CubeMX-5.4.0.linux就是Linux下的安装脚本,安装完成后,使用手册在安装目录下的help/UM1718.pdf里,11~19 章是具体的示例教程.Linux 安装后运行截图如下:
    STM32CubeMX.png
  • 如上图所示,可以安装相应的嵌入式的软件,就是各种MCU的库文件,模版文件,也可以通过手动下载,如:STM32Cube MCU Package for STM32F7 series .
  • 也可以通过这里这种几只平台的发行版本包.
  • Linux 下安装完成,它没有自动在系统菜单添加条目录.可以参照下面路径与文件格式新建一个用户菜单项.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~$ cat ~/.local/share/applications/stm32cubemx.desktop
[Desktop Entry]
Type=Application
Name=STM32CubeMX
GenericName=STM32CubeMX
Comment=STM32CubeMX
Terminal=false
Categories=Development;IDE;Electronics;
Keywords=embedded electronics;electronics;avr;microcontroller;
Exec=/home/michael/IDE_DIR/STM32CubeMX-5.4/STM32CubeMX
Terminal=false
# 这里要安装了相应的插件在才有的.
Icon=/home/michael/.p2/pool/plugins/com.st.stm32ide.common.utils_1.0.0.201902141520/icons/stm32cube 32x32.png
Categories=GNOME;GTK;Development;
StartupNotify=true

# 保存上面文件,更新系统菜单项.
~$ update-menus

STSW-STM32095 Eclipse 插件

  • 下载STSW-STM32095到本地,打开 Eclipse,进入Help-->Installl New Software... --> 点击 Add --> 在Name里输入一个名字,--> 点击 Archive... --> 选择刚才下载的en.stsw-stm32095.zip --> 确定进行安装.
  • 安装完成后,在 Eclipse 里可以通过右上角的图标打开STM32CubeMXPerspective, 也可以通过菜单栏Windows-->Perspective-->Open Perspective-->Other 选择STM32CubeMX打开,打开的界面如同上面的STM32CubeIDE原生界面.

STM32CubeMX 创建工程

创建基于 STM32F4-discovery 评估板的工程

  • 在初次打开STM32CubeMX时可能会从通过网络去到ST官网下载一些默认的BSP支持文件,还有在新建项目时,如果本地没有相关的文件件,它也会自动去官网下载,所以联网是必须的.

新建工程

  • 打开File -> New Project -> Board Selector,右边栏显示所有支持的板子型号,左边栏可以通过一些参数过滤,找到我们要匹配的板子型号.Type -> Discovery kit, MCU/MPU Series -> STM32F4,这里大概会列表 7 个候选板子,我选择最后一个,点击右上解Start Project,它会联网下载一些文件,完成后就会打开一个配置界面.

配置 Pinout & Configuration

  • 中间件 FreeRTOS,配置如下:
    f407-rtos-freertos.png

  • USB OTG,配置如下:
    f407-rtos-usb-otg.png

  • USB Device,配置如下:
    f407-rtos-freertos.png

  • GPIO,如果我这里要点亮某些板子上的 LED,在这里需要配置好相应的 GPIO 模式.配置如下:
    f407-rtos-gpio.png

  • USART2,串口通讯配置如下:
    f407-rtos-usart2.png

配置 Clock Configuration

  • 注意,这里的时钟树配置与上面的 Pinout 配置会有相互影响,比如:各种复用功能之间的资源冲突, 这里需要根据手册去调整.

    f407-rtos-clock.png

配置工程

  • 在配置完成上述功能,可以打开Project Manager页面,主要配置的是Project页面里的参数,注意Heap与Stack的大小是否合适,比如Toolchain/IDE这里有几个选项, 支持不同的厂商 IDE 如,IAR,MDK-ARM,TrueStudio 等, 我这边会选择SW4STM32类型,使用 Eclipse 在 Linux 下导入它,应该还可以选择Makefile类型,也可以通过 Eclipse 导入.至于Code Generator页面里,保持默认选择Copy only the necessary library files就可以了,不然会把工程文件搞大吗?完成后,点击右上角GENERATE CODE生成代码,再完成之后,可以直接打开目录查看生成的代码.
  • f407-rtos-project-cfg.png

安装 OpenSTM32 环境

  • Importing a STCubeMX generated project

  • System Workbench for STM32

  • Linux环境下,我这里选择Eclipse做为开发IDE,但是要安装一个插件,请参考ST官网SW4STM32.这里两种方式安装:

    • 1.下载 Linux 安装程序.
      • 这里其实包含一个完整 EclipseSystemWorkbench 的安装包,如果系统已经有 Eclipse 了可以选择第二种安装方式(插件安装),独立安装如图:
        SystemWorkbench.png
    • 2.添加Eclipse插件源,从Eclipse 安装,Help-->Installl New Software... --> Add,在 location 里输入http://ac6-tools.com/Eclipse-updates/org.openstm32.system-workbench.update-site-v2,点击 OK 新建一个更新站点.
      • 但是因为网络原因,通过http://www.ac6-tools.com/Eclipse-updates/org.openstm32.system-workbench.update-site-v2/安装会很慢,而且会断线.所以这里会先使用 wget -r -np -nH -R -c http://www.ac6-tools.com/Eclipse-updates/org.openstm32.system-workbench.update-site-v2/把它的网站目录下载到本地.进入到 org.openstm32.system-workbench.update-site-v2使用find . -iname "index.*"清除这些无用的index.html文件,还可以用此脚本清除一些旧版的 jar,减小体积.再通过Help-->Installl New Software... --> Add创建一个 本地安装源 如 openstm32 - file:/home/lcy/Downloads/Eclipse-updates/org.openstm32.system-workbench.update-site-v2/ 就可以正常使用了. 更新后会出现:
      • External Tools # 这里出现版偏旧,可以参考使用 https://github.com/gnu-mcu-eclipse/eclipse-plugins
        • ARM Compiler for MCU
        • OpenOCD
        • STLinkServer
      • OpenSTM32 Tools
      • STM32-Copro-MPU
    • 这里就把上面三个大选项都选上安装.

导入 STM32CubeMX 生成工程文件

  • 打开 Eclipse,从File -> Import...,选择General组下的Existing Projects into Workspace,会打开导入工程对话框.根目录选择在STM32CubeMX --> Project Manager里的工程配置页里工程生成路径,如图:
    ac6-prj-import.png

重命名生成的工程

  • 右键project->Properties,进入到C/C++ Build -> Settings -> Build Artifact
    /imgs/stmcubemx/prj-rename.png

指定交叉编译工具链

  • 在右键project->Properties,进入到C/C++ Build -> Settings -> Tools Settings -> MCU Setings里面的 path 值是${openstm32_compiler_path},这里出现找不到arm-none-eabi-gcc的错误提示.把这个变量名换成它带的ARM Compiler for MCU工具链的安装绝对路径就可以正常编译了.ARM Compiler for MCU工具链默认是解压在插件路径里,也可以复制到其它的路径里.这里把上述path里的变量改成/home/michael/IDE_DIR/Ac6/SystemWorkbench/plugins/fr.ac6.mcu.externaltools.arm-none.linux64_1.17.0.201812190825/tools/st-gnu-arm-gcc-7-2018-q2-update_gdb-5_4-2016q3/bin后,成功编译.如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
Building file: ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c
Invoking: MCU GCC Compiler
/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Debug
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 '-D__weak=__attribute__((weak))' '-D__packed="__attribute__((__packed__))"' -DUSE_HAL_DRIVER -DSTM32F407xx -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Inc" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Drivers/STM32F4xx_HAL_Driver/Inc" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Drivers/STM32F4xx_HAL_Driver/Inc/Legacy" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Middlewares/Third_Party/FreeRTOS/Source/include" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Middlewares/ST/STM32_USB_Device_Library/Core/Inc" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Drivers/CMSIS/Device/ST/STM32F4xx/Include" -I"/home/michael/eclipse-workspace/stm32f407_discovery_rtos/Drivers/CMSIS/Include" -Og -g3 -Wall -fmessage-length=0 -ffunction-sections -c -fmessage-length=0 -MMD -MP -MF"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.d" -MT"Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.o" -o "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.o" "../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c"
Finished building: ../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c

Building target: stm32f407_rtos.elf
Invoking: MCU GCC Linker
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nosys.specs -specs=nano.specs -T"../STM32F407VGTx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -o "stm32f407_rtos.elf" @"objects.list" -lm
Finished building target: stm32f407_rtos.elf

make --no-print-directory post-build
Generating hex and Printing size information:
arm-none-eabi-objcopy -O ihex "stm32f407_rtos.elf" "stm32f407_rtos.hex"
arm-none-eabi-size "stm32f407_rtos.elf"
text data bss dec hex filename
26768 492 27996 55256 d7d8 stm32f407_rtos.elf


21:34:37 Build Finished. 0 errors, 0 warnings. (took 12s.463ms)

测试流水灯代码

  • 因为在STM32CubeMX加入了 FreeRTOS 的模块,所以 main.c 有一些系统相关的代码,下面只在 main.c 里的 while(1)里,简单测板上的四个流水灯.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//  osKernelInitialize();
// const osThreadAttr_t defaultTask_attributes = {
// .name = "defaultTask",
// .priority = (osPriority_t) osPriorityNormal,
// .stack_size = 128
// };
// defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
// osKernelStart();
// 需要注释上面的代码才能运行到while这里.
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);
HAL_Delay(500);//毫秒级延迟
HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);
HAL_Delay(500);
HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);
HAL_Delay(500);
HAL_GPIO_TogglePin(LD6_GPIO_Port,LD6_Pin);
HAL_Delay(500);

/* USER CODE BEGIN 3 */
}
  • 添加上述代码,重新编译,连接上开发板,选择工程右键Run As -> Ac6 STM32 C/C++ Application就会下载代码到开发板,会看四个 LED 轮流慢闪.也可以运行Debug As单步调试每一条指令.

谢谢支持

服务端安装

快速安装

1
2
3
4
5
6
7
# for debian systems, installs dokku via apt-get

~$ wget https://raw.githubusercontent.com/dokku/dokku/v0.23.8/bootstrap.sh

~$ sudo DOKKU_TAG=v0.23.8 bash bootstrap.sh

# go to your server's IP and follow the web installer

使用ansible安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 参考位置 http://dokku.viewdocs.io/dokku/getting-started/install/debian/ 改编的文件
- name: 安装Dokku
hosts: DB001
become: yes
# user: root 这里可以直接用root,但是关闭root远程登录后要使用sudo.
tasks:
# 参照文档 https://docs.ansible.com/ansible/latest/modules/apt_module.html
- name: 更新并安装
apt:
name: ['apt-transport-https', 'wget']
allow_unauthenticated: yes
update_cache: yes

- name: 添加公钥
apt_key:
url: https://packagecloud.io/gpg.key
validate_certs: no
state: present

# 参考文档 https://docs.ansible.com/ansible/latest/modules/command_module.html#command-module
- name: 读取系统发行版本号
command: lsb_release -sc
register: result

# https://docs.ansible.com/ansible/latest/modules/stat_module.html?highlight=stat 读取文件的stat
- stat:
path: /etc/apt/sources.list.d/dokku_dokku.list
register: dokku_repo

# https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html
# 把几个任务组合起来,用条件判断.
- block:
# https://docs.ansible.com/ansible/latest/modules/get_url_module.html?highlight=get_url
- name: 下载安装脚本
get_url:
url: https://packagecloud.io/install/repositories/dokku/dokku/script.deb.sh
dest: /tmp/script.deb.sh
validate_certs: no
force: yes
mode: 0755

# https://docs.ansible.com/ansible/latest/modules/script_module.html
# 也可以从这里直接下载deb安装包. https://packagecloud.io/dokku/dokku/
- name: 运行安装Dokku脚本
command: bash /tmp/script.deb.sh
when: dokku_repo.stat.exists is not defined or dokku_repo.stat.size == 0

- name: 安装dokku
apt:
name: ['dokku']
allow_unauthenticated: yes
update_cache: yes

# https://docs.ansible.com/ansible/latest/modules/debconf_module.html
- name: unattended installation of dokku
debconf:
name: dokku
question: dokku/vhost_enable
value: 'true'
vtype: select

- name: 安装Dokku依赖
command: dokku plugin:install-dependencies --core
  • 安装完成后会启动一个http-server提供 web 方式的配置,浏览器输入服务器 ip 打开页面,输入公钥和域名(或者公网 IP)就 OK.

客户端安装

  • dokku-client 这个客户端很久没有更新的了,不支持 python3.

  • 官方客户端,这里基于不同语言有比较全面的客户端介绍.

  • Deploying Django on Dokku

  • 这里使用官方的提供的客户端脚本,如下面所示,运行脚本前,先要确定几个重点,

    • 添加DOKKU_HOST环境变里,或者直接写入$HOME/.dokku/contrib/dokku_client.sh这个脚本里面.
    • 能使用公钥登录目标dokku服务器.
  • dokku服务器端加入一个可信的客户端公钥,操作如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 列出本机加入的可信公钥
    ~$ dokku ssh-keys:list
    SHA256:Lr2N48k+1UDb0IxxWm0AhI0fzpdpnEZtalGc+XXXXX NAME="admin1" SSHCOMMAND_ALLOWED_KEYS="no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding"
    # 添加一个客户端的公钥
    ~$ sudo dokku ssh-keys:add admin2 /fullpath/id_rsa.pub
    SHA256:diDyzHYBmugZoGkWw1RaqzGkLfdCUpmBOxXFnf/XXXX
    ~$ dokku ssh-keys:list
    SHA256:Lr2N48k+1UDb0IxxWm0AhI0fzpdpnEZtalGc+Pf7Rvo NAME="admin1" SSHCOMMAND_ALLOWED_KEYS="no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding"
    SHA256:diDyzHYBmugZoGkWw1RaqzGkLfdCUpmBOxXFnf/XXXX NAME="admin2" SSHCOMMAND_ALLOWED_KEYS="no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding"
  • 下载客户端仓库.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ~$ git clone git@github.com:dokku/dokku.git ~/.dokku

    # optional: make sure that the dokku_client.sh version matches your Dokku version
    ~$ cd ~/.dokku
    ~$ git checkout <tag/branch>

    # add the following to either your
    # .bashrc, .bash_profile, or .profile file
    ~$ alias dokku='$HOME/.dokku/contrib/dokku_client.sh'
  • 正常的客户端运行如下,与heroku的客户端命令极其相似.如果运行dokku无任何输出,你要查看SSH连接信息是否正确,DOKKU_PORT,DOKKU_HOST的的环境变量是否与目标服务器匹配.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    ~$ dokku
    Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND <app> [command-specific-options]

    Primary help options, type "dokku COMMAND:help" for more details, or dokku help --all to see all commands.

    Commands:

    apps Manage Dokku apps
    certs Manage Dokku apps SSL (TLS) certs
    checks Manage zero-downtime settings
    config Manages global and app-specific config vars
    docker-options Pass options to Docker the various stages of an app
    domains Manage vhost domains used by the Dokku proxy
    enter Connect to a specific app container
    events Show the last events (-t follows)
    git Manages the git integration for an app
    help Print the list of commands
    logs Output app logs
    network Manages network settings for an app
    nginx Interact with Dokku\'s Nginx proxy
    proxy Manage the proxy used by dokku on a per app
    ps List processes running in app container(s)
    repo Runs commands that interact with the app\'s repo
    run Run a command in a new container using the current application image
    scheduler-docker-local Manages the scheduler-docker-local integration for an app
    shell Spawn dokku shell
    ssh-keys Manage public ssh keys that are allowed to connect to Dokku
    storage Mount local volume / directories inside containers
    tags List all app image tags
    tar Deploy applications via tarball instead of git
    trace Enable dokku tracing
    url Show the first URL for an application (compatibility)
    urls Show all URLs for an application
    version Print dokku\'s version

    ~$ dokku plugin:list
    ! Deprecated: Please use plugin:list
    plugn: 0.3.0
    00_dokku-standard 0.14.1 enabled dokku core standard plugin
    20_events 0.14.1 enabled dokku core events logging plugin
    app-json 0.14.1 enabled dokku core app-json plugin
    apps 0.14.1 enabled dokku core apps plugin
    build-env 0.14.1 enabled dokku core build-env plugin
    certs 0.14.1 enabled dokku core certificate management plugin
    checks 0.14.1 enabled dokku core checks plugin
    common 0.14.1 enabled dokku core common plugin
    config 0.14.1 enabled dokku core config plugin
    docker-options 0.14.1 enabled dokku core docker-options plugin
    domains 0.14.1 enabled dokku core domains plugin
    enter 0.14.1 enabled dokku core enter plugin
    git 0.14.1 enabled dokku core git plugin
    logs 0.14.1 enabled dokku core logs plugin
    network 0.14.1 enabled dokku core network plugin
    nginx-vhosts 0.14.1 enabled dokku core nginx-vhosts plugin
    plugin 0.14.1 enabled dokku core plugin plugin
    proxy 0.14.1 enabled dokku core proxy plugin
    ps 0.14.1 enabled dokku core ps plugin
    repo 0.14.1 enabled dokku core repo plugin
    scheduler-docker-local 0.14.1 enabled dokku core scheduler-docker-local plugin
    shell 0.14.1 enabled dokku core shell plugin
    ssh-keys 0.14.1 enabled dokku core ssh-keys plugin
    storage 0.14.1 enabled dokku core storage plugin
    tags 0.14.1 enabled dokku core tags plugin
    tar 0.14.1 enabled dokku core tar plugin

部署Django工程实例

  • 简化 Django 开发的八个 Python 包

  • Django 使用 Celery 实现异步任务

  • django-allauth 认证模块

  • 下面的环境基于Pyenv+Pipenv.Pyenv: python 版本管理器.Pipenv: python 包管理器,更好用的 pip.

  • pyenv的一些基本操作.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    # pyenv 安装的位置
    ~$ which pyenv
    /home/lcy/.pyenv/bin/pyenv

    # pyenv 可提供的安装版本.
    ~$ pyenv install --list
    Available versions:
    2.1.3
    2.2.3
    2.3.7
    2.4
    2.4.1
    2.4.2
    2.4.3
    2.4.4
    [...]

    # 本机已经安装的版本
    ~$ pyenv versions
    system
    * 3.6.6 (set by /home/lcy/.python-version)
    3.6.6/envs/dokku-py3
    3.6.6/envs/py3dev
    dokku-py3
    py3dev

    # 本机默认使用的版本.
    ~$ pyenv version
    3.6.6 (set by /home/lcy/.python-version)
    # 为这个版本安装pipenv
    ~$ pip install pipenv
    Collecting pipenv
    # 列出当前安装的包.
    ~$ pip list
    Package Version
    ---------------- ----------
    autopep8 1.4
    certifi 2018.11.29
    pip 18.1
    pipenv 2018.11.26
    pycodestyle 2.4.0
    setuptools 39.0.1
    virtualenv 16.2.0
    virtualenv-clone 0.4.0
    yapf 0.23.0
  • 通过上述命令安装了pipenv,下面是它的一些基本操作.官方文档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # 创建python3的虚拟环境,也可以用 pipenv --python 3.7 指定具体的版本号.
    ~$ pipenv --three
    Creating a virtualenv for this project…
    Pipfile: /home/lcy/workspace/dokku-test/crm/Pipfile
    Using /home/lcy/.pyenv/versions/3.6.6/bin/python3.6 (3.6.6) to create virtualenv…
    ⠸ Creating virtual environment...Already using interpreter /home/lcy/.pyenv/versions/3.6.6/bin/python3.6
    Using base prefix '/home/lcy/.pyenv/versions/3.6.6'
    New python executable in /home/lcy/.local/share/virtualenvs/crm-GMqHkluo/bin/python3.6
    Also creating executable in /home/lcy/.local/share/virtualenvs/crm-GMqHkluo/bin/python
    Installing setuptools, pip, wheel...
    done.

    ✔ Successfully created virtual environment!
    Virtualenv location: /home/lcy/.local/share/virtualenvs/crm-GMqHkluo
    Creating a Pipfile for this project…
    # 查看环境位置.
    ~$ pipenv --venv
    /home/lcy/.local/share/virtualenvs/crm-GMqHkluo

    ~$ pipenv --py
    /home/lcy/.local/share/virtualenvs/crm-GMqHkluo/bin/python

    # 安装django依赖包.当前工程目录下的Pipfile.lock文件,就等同于传统的requirements.txt文件.
    ~$ pipenv install django django-toolbelt
    Installing django…
    Adding django to Pipfile\'s [packages]…
    ✔ Installation Succeeded
    Installing django-toolbelt…
    Adding django-toolbelt to Pipfile\'s [packages]…
    ✔ Installation Succeeded
    Pipfile.lock not found, creating…
    Locking [dev-packages] dependencies…
    Locking [packages] dependencies…
    ✔ Success!
    Updated Pipfile.lock (c14d8c)!
    Installing dependencies from Pipfile.lock (c14d8c)…
    🐍 ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 8/8 — 00:00:01
    To activate this project\'s virtualenv, run pipenv shell.
    Alternatively, run a command inside the virtualenv with pipenv run.
    # 列出安装包的的依赖.
    ~$ pipenv graph
    django-toolbelt==0.0.1
    - dj-database-url [required: Any, installed: 0.5.0]
    - dj-static [required: Any, installed: 0.0.6]
    - static3 [required: Any, installed: 0.7.0]
    - django [required: Any, installed: 2.1.5]
    - pytz [required: Any, installed: 2018.9]
    - gunicorn [required: Any, installed: 19.9.0]
    - psycopg2 [required: Any, installed: 2.7.6.1]
    # 进入pipenv 虚拟环境shell
    ~$ pipenv shell
    Launching subshell in virtual environment…
    . /home/lcy/.local/share/virtualenvs/cms-uhqZcysp/bin/activate

创建Django的示例项目.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
~$ mkdir dokkutest && cd dokkutest
~$ pipenv --three
Creating a Pipfile for this project…
# 会在本机目录下生成一个Pipfile
~$ cat Pipfile
[[source]]
name = "pypi"
#url = "https://pypi.org/simple"
#使用阿里云源
url = "http://mirrors.aliyun.com/pypi/simple"
verify_ssl = true

# 使用阿里云源必需加这一行.
[install]
trusted-host = mirrors.aliyun.com

[dev-packages]

[packages]

[requires]
python_version = "3.6"
# 安装相应的包.
~$ pipenv install django django-toolbelt
~$ pipenv shell
~$ django-admin.py startproject dokkutest .
~$ echo "web: gunicorn dokkutest.wsgi" > Procfile
~$ echo "venv" > .gitignore
# 新建APP
~$ django-admin.py startapp webui
# 安装APP
~$ sed -i "/django.contrib.staticfiles/ a\ 'webui'," dokkutest/settings.py
# 如果不加这两行,就要设置 dokku config:set DISABLE_COLLECTSTATIC=1,不然会出错,强烈建议加下面一行.
~$ sed -i "/STATIC_URL/ a\STATIC_ROOT = os.path.join(BASE_DIR, 'static')" dokkutest/settings.py
# 本地合并
~$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
[....]
# 本的运行测度
$ python manage.py runserver 0.0.0.0:9000
Performing system checks...

System check identified no issues (0 silenced).
January 14, 2019 - 09:03:32
Django version 2.1.5, using settings 'dokkutest.settings'
Starting development server at http://0.0.0.0:9000/
Quit the server with CONTROL-C.
# 收集依赖包的列表,这里会收集当前虚环境的所有包,建议新建工程时新建一个新的虚拟环境,
# 这样可以保证requirements.txt是最小的依赖列表.
~$ pip freeze -l > requirements.txt
# 添加Procfile文件.
~$ echo "web: gunicorn dokkutest.wsgi" > Procfile
# 指定python的版本
~$ echo "python-3.6.7" > runtime.txt
# 加入git版本管理,这里假设我的dokku服务器的<域名>地址是172.16.10.100
~$ git init
~$ git add .
~$ git commit -m 'first commit'
~$ git remote add dokku dokku@172.16.10.100:dokkutest
# push代码后,就触编译与发布.
~$ git push dokku master
Delta compression using up to 6 threads.
Compressing objects: 100% (29/29), done.
Writing objects: 100% (33/33), 8.11 KiB | 0 bytes/s, done.
Total 33 (delta 5), reused 0 (delta 0)
-----> Cleaning up...
-----> Building dokkutest from herokuish...
-----> Adding BUILD_ENV to build environment...
-----> Python app detected
Skipping installation, as Pipfile.lock hasn\'t changed since last deploy.
[....]
DOKKU_APP_RESTORE: 1
=====> Renaming container (b7192f0ff943) dreamy_pascal to dokkutest.web.1
=====> Application deployed:
http://172.16.10.100:51903 # 到此程序的窗口与宿主机的端口映射已经生成了.

To 172.16.10.100:dokkutest
* [new branch] master -> master

~$ dokku apps:list
=====> My Apps
dokkutest
# dokku 服务器里的docker对应的容器运行起来
~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7192f0ff943 dokku/dokkutest:latest "/start web" 23 hours ago Up 23 hours dokkutest.web.1
# 端口映射OK
~$ netstat -tnlp
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:51903 0.0.0.0:* LISTEN -

# 应用在服务器的位置,一些配置文件与变量可以直接进入服务器里的相关app目录下去修改.
~$ tree -L 1 /home/dokku
/home/dokku
├── bazi
├── ENV
├── HOSTNAME
├── phpcms
├── VERSION
└── dokkutest

Dokku其它指南

  • 设置APP域名.如上面所述,app 映射了一个很大端口值http://172.16.10.100:51903,只能通过 IP+端口的方式访问,这有可能不能满足我们的实际应用需求,怎样在同一个IP里使用不同的域名访问不同的应用呢?或者说,同一个服务器里的应用都想通过80端口对外提供服务.这里就要通过nginx代理不同的域名.命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~$ dokku domains:help
Usage: dokku domains[:COMMAND]

Manage vhost domains used by the Dokku proxy.

Additional commands:
domains:add <app> <domain> [<domain> ...] Add domains to app
domains:add-global <domain> [<domain> ...] Add global domain names
domains [<app>] [DEPRECATED] Alternative for domains:report
domains:clear <app> Clear all domains for app
domains:disable <app> Disable VHOST support
domains:enable <app> Enable VHOST support
domains:remove <app> <domain> [<domain> ...] Remove domains from app
domains:remove-global <domain> [<domain> ...] Remove global domain names
domains:report [<app>] [<flag>] Displays a domains report for one or more apps
domains:set <app> <domain> [<domain> ...] Set domains for app
domains:set-global <domain> [<domain> ...] Set global domain names
  • 为 dokkutest  这个应用设置 test.example.com 这个域名,后面就可以通过个域名 80 端就能访问到这个应用了.
1
2
3
4
5
~$ dokku domains:test.example.com  dokkutest
[...]
=====> 734565b29c3d49d4e9ae129b79c8011353300f45380a4b1fdce0df9604c2d31b
=====> Application deployed:
http://test.example.com
  • 访问静态资源.其实上面的部署是一个基本的应用,做一个Restful API服务器是没有问题的.如果做成网页端,它的static下的静态资源是不能访问的.这里要用到一些其它包与设置.具体参照这里 Django and Static Assets.具体解决如下:
1
2
3
4
5
6
7
8
9
# 安装whitenoise
~$ pip install whitenoise
# 下面修改settings.py
MIDDLEWARE_CLASSES = (
# 放在最上层一行.
# https://warehouse.python.org/project/whitenoise/
'whitenoise.middleware.WhiteNoiseMiddleware',
# 添加这一行
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Dokku插件应用

letsencrypt

1
2
3
4
# 安装
~$ sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
# 更新
~$ sudo dokku plugin:update letsencrypt
  • APP安装Lets'Encrypt,这里需要注意,这个app设置了三个域名,其中只有一个是在 DNS 上设置的h5.lcy.wiki,所以才会出现下面的错误.只要把其它两个域名从这个app中删除就可以了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
~$ dokku letsencrypt h5dev
=====> Let\'s Encrypt h5dev
-----> Updating letsencrypt docker image...
[...]
-----> Enabling ACME proxy for h5dev...
-----> Getting letsencrypt certificate for h5dev...
- Domain 'h5dev.www.lcy.wiki'
- Domain 'h5.lcy.wiki'
- Domain 'h5dev'
[...]
ACME server returned an error: urn:acme:error:malformed ::\n
The request message was malformed :: Error creating new authz :: DNS name does not have enough labels


Debugging tips: -v improves output verbosity. Help is available under --help.
-----> Certificate retrieval failed!
-----> Disabling ACME proxy for h5dev...
done
# 正常应该如下所示

~$ dokku domains:report h5dev
=====> h5dev domains information
Domains app enabled: true
Domains app vhosts: h5.lcy.wiki

~$ dokku letsencrypt:ls
-----> App name Certificate Expiry Time before expiry Time before renewal
h5dev 2019-06-18 18:42:21 89d, 20h, 14m, 52s 59d, 20h, 14m, 52s

# 自动刷新证书
~$ dokku letsencrypt:auto-renew h5dev
h5dev still has 59d, 20h, 12m, 43s days left before renewal

redis插件应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
~$ sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
~$ dokku redis:create dokku-redis
~$ dokku redis:info dokku-redis
=====> Container Information
# 这两行是映射到宿主机的实际目录下面.
Config dir: /var/lib/dokku/services/redis/dokku-redis/config
Data dir: /var/lib/dokku/services/redis/dokku-redis/data
Dsn: redis://dokku-redis:df40bbae8555ab43ff946605e4c@dokku-redis-dokku-redis:6379
Exposed ports: -
Id: e535a815b6bdc6898c9e6615d2e3fe0dd7387598bc6795aaf0529ad998b2f114
Internal ip: 172.17.0.8
Links:
Service root: /var/lib/dokku/services/redis/dokku-redis
Status: running
Version: redis:4.0.11
  • 连接 redis 与容器应用服务
1
2
3
4
5
6
7
8
9
10
11
12
13
~$ dokku redis:link dokku-redis  yfh5
-----> Setting config vars
REDIS_URL: redis://dokku-redis:df40bbae8555ab43ff946605e4c@dokku-redis-dokku-redis:6379
-----> Restarting app yfh5
-----> Releasing yfh5 (dokku/yfh5:latest)...
[...]

~$ dokku redis:info dokku-redis
[...]
Internal ip: 172.17.0.8
Links: yfh5
Service root: /var/lib/dokku/services/redis/dokku-redis
[...]
  • 添加到Django项目中用作Sessiong Cache,修改settings.py的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

CACHES = {
"default": {
"BACKEND":
"django_redis.cache.RedisCache",
"LOCATION":
"redis://dokku-redis:df40bbae8555ab43ff946605e4c@dokku-redis-dokku-redis:6379",
"OPTIONS": {
"DB":
0,
"PASSWORD":
"df40bbae8555ab43ff946605e4c",
"CONNECTION_POOL_KWARGS": {
"max_connections": 65535
},
}
}
}

设置 Settings.py

  • How to deploy Django on Dokku
  • Dokku Environment Variables
  • 因为Django开发测试需要与数据库连接,且开发环境与生产(测试)部署的环境是不一样的,这里可以通过在settings.py判断系统环境变理来做出一些自动化.上面那个链接很有参考意.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    # We should get this from the environment, never store them in git.
    # 为了安全建义不要SECRET_KEY直接写入settings.py,它会保存在git上面记录.
    # 可以使用 dokku config:set appname SECRET_KEY='xxxxxx'
    SECRET_KEY = os.environ.get("SECRET_KEY", 'secret')

    # Set DEBUG to False if the NODEBUG env var has been set.
    DEBUG = True if os.environ.get("NODEBUG") is None else False

    # Set the allowed hosts based on the environment.
    ALLOWED_HOSTS = ["web", "localhost"] if os.environ.get("NODEBUG") is None else [".yourdomain.com"]

    if os.environ.get("IN_DOCKER"):
    # Stuff for when running in Docker-compose.
    # 使用Docker-compose会有IN_DOCKER这个环境变量

    CELERY_BROKER_URL = 'redis://redis:6379/1'
    CELERY_RESULT_BACKEND = 'redis://redis:6379/1'
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': "postgres",
    'USER': 'postgres',
    'PASSWORD': 'password',
    'HOST': "db",
    'PORT': 5432,
    }
    }
    elif os.environ.get("DATABASE_URL"):
    # Stuff for when running in Dokku.

    # Parse the DATABASE_URL env var.
    regex = "^postgres://(?P<username>.*?)\:(?P<password>.*?)\@(?P<host>.*?)\:(?P<port>\d+)\/(?P<db>.*?)$"
    USER, PASSWORD, HOST, PORT, NAME = re.match(regex, os.environ.get("DATABASE_URL", "")).groups()

    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': NAME,
    'USER': USER,
    'PASSWORD': PASSWORD,
    'HOST': HOST,
    'PORT': int(PORT),
    }
    }

    CELERY_BROKER_URL = os.environ.get("REDIS_URL", "") + "/1"
    CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL", "") + "/1"
    else:
    # Stuff for when running locally.

    CELERY_TASK_ALWAYS_EAGER = True
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
    }

Mysql插件应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
~$ sudo dokku plugin:install https://github.com/dokku/dokku-mysql.git mysql
# 创建数据库服务
~$ sudo dokku mysql:create dyt
Waiting for container to be ready
=====> MySQL container created: dyt
=====> Container Information
Config dir: /var/lib/dokku/services/mysql/dyt/config
Data dir: /var/lib/dokku/services/mysql/dyt/data
Dsn: mysql://mysql:42b0d88fb443bab7@dokku-mysql-dyt:3306/dyt
Exposed ports: -
Id: 45171e69490d59524728846297870ca3010d0066e9972f00448b95bf8bbe86d2
Internal ip: 172.17.0.10
Links: -
Service root: /var/lib/dokku/services/mysql/dyt
Status: running
Version: mysql:5.7.12
# 把应用与数库服务连接起来
~$ sudo dokku mysql:link dyt phpenroll
-----> Setting config vars
DATABASE_URL: mysql://mysql:42b0d88fb443bab7@dokku-mysql-dbname:3306/dyt
-----> Restarting app phpenroll

# 备价与恢复
~$ dokku mysql:export [db_name] > [db_name].dump
~$ dokku mysql:import [db_name] < [db_name].dump
# 进入数据库
~$ dokku mysql:connect dyt
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| dyt |
+--------------------+
2 rows in set (0.00 sec)

# 注意,dokku 创建的数据服务,里面只有一个与服务名相同的数据库,同时也不能通过mysql命令进去创建新的数据库,用户与授权.

Persistent Storage

  • 参考链接
  • 这里需要在主机上先建一个目录,供给容器内挂载,官方推荐是/var/lib/dokku/data/storage,这里可以是其它文件系统目录如:cephfs,nfs等. 关于volume与主机共享数据使用,也可以参考http://dokku.viewdocs.io/dokku/advanced-usage/docker-options/.如:dokku docker-options:add node-js-app deploy,run "-v /var/log/node-js-app:/app/logs"
1
2
~$ sudo dokku plugin:install storage
~$ dokku storage:mount node-js-app /var/lib/dokku/data/storage/node-js-app:/storage

常见的错误

1
2
3
~$ -----> Python app detected
! Requested runtime (python-3.6.7) is not available for this stack (heroku-16).
! Aborting. More info: https://devcenter.heroku.com/articles/python-support
  • 如果出现上述错误,请重新安装.

与 WebPack 集成

谢谢支持

安装 Eclipse 插件

  • 打开 Eclipse 的Help->Install New Software....,添加一个新的 URL 安装源,这里填入 Stable 版的http://gnu-mcu-eclipse.netlify.com/v4-neon-updates.

  • 更新并选择安装GNU ARM & RISC-V C/C++ Cross Development Tools所有的插件.

  • 新建一个工程,选择 C Project 模版会出现如下图:
    gnu-mcu-eclipse-cproject.jpg

  • 新建工程最后一步,显示选择并配置GNU ARM Cross ToolChain交叉工具链,默认名是GNU MCU Eclipse ARM Embedded GCC (arm-none-eabi-gcc)相应的工具链包可以从网上https://launchpad.net/gcc-arm-embedded/+download下载,并在这里指定的它的解压路径.

OpenOCD 安装配置

  • 这里可以结合前面 Codeblocks 里的 openocd 安装.还有GNU MCU Eclipse Debug 部分
  • 截图如下:
    ![The OpenOCD debugging Eclipse plug-in.jpg](/imgs/TheOpenOCD debuggingEclipseplug-in.jpg)

STM32 模版工程配置

新建工程

  • 可以参照它的官网STM32Fxx templates
  • 或者它的截图如下:
    ![STM32Fxx templates.png](/imgs/STM32Fxx templates.png)

CMSIS 包管理

  • 原文参照The CMSIS Packs manager
  • 截图如下:
  • ![The CMSIS Packs manager.jpg](/imgs/The CMSIS Packs manager.jpg)

安装 QEMU 调试模拟器

谢谢支持

软件定义电台

rtl-sdr

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
~$ sudo apt-get install rtl-sdr

~$ rtl_eeprom
Found 1 device(s):
0: Generic RTL2832U OEM

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner

Current configuration:
__________________________________________
Vendor ID: 0x0bda
Product ID: 0x2838
Manufacturer: Realtek
Product: RTL2838UHIDIR
Serial number: 00000001
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no

收音机功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~$ rtl_fm -f 87.0e6 -M wbfm -s 200000 -r 48000 - | aplay -r 48 -f S16_LE
Found 1 device(s):
0: Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Tuner gain set to automatic.
Tuned to 87216000 Hz.
Oversampling input by: 6x.
Oversampling output by: 1x.
Buffer size: 6.83ms
Sampling at 1200000 S/s.
Output at 200000 Hz.
Playing raw data 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono

gr-air-modes 使用

编译

  • 这里请参照该项目的README.md指导安装.
1
2
3
4
~$ git clone https://github.com/bistromath/gr-air-modes
~$ cd gr-air-modes && mkdir build
~$ cd build
~$ cmake ../

收集飞行数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
~$ modes_rx -s osmocom -t 1234 -r 2.4e6 --kml air-tracker.kml
linux; GNU C++ version 6.3.0 20170221; Boost_106200; UHD_003.009.005-0-unknown

gr-osmosdr 0.1.4 (0.1.4) gnuradio 3.7.10
built-in source types: file osmosdr fcd rtl rtl_tcp uhd miri hackrf bladerf rfspace airspy soapy redpitaya
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
Found Rafael Micro R820T tuner
Using device #0 Realtek RTL2838UHIDIR SN: 00000001
Found Rafael Micro R820T tuner
[R82XX] PLL not locked!
[R82XX] PLL not locked!
Gain is 33
Rate is 2400000
(-26 0.06682075) Type 17 BDS0,9-1 (track report) from 780d1c with velocity 458kt heading 268 VS -64
(-40 0.07617875) No handler for message type 24 from 19f157
(-38 0.15085075) Type 0 (short A-A surveillance) from adae05 at 4375ft (speed <75kt)
[...]

读取飞行数据

gpsprune

  • Debian 系统可以通过系统直接安装.
1
2
3
~$ sudo apt-get install gpsprune -y
[...]
~$ gpsprune
  • 通过File-->Open File,打开对话框,找到并选择air-tracker.kml文件,就会看到如下图所示的界面,一些蓝色的线条与点,把上面的小地球点亮就会加载地图进来.

![gpsprune]](/imgs/rtl-sdr/gpsprune.png)

Google Earth

  • 从谷歌网站去下载地图软件,这里是需要科学上网才能下载与使用的.
1
~$ sudo dpkg -i google-earth-pro-stable_current_amd64.deb
  • 打开软件Add-->Network Link如下图所示,打开对话框,找到并选择air-tracker.kml文件.

add-link

  • 可以根据需要,设置Refresh,如:自动刷新…

google-map.png

GnuRadio

源码安装

安装Volk

1
2
3
4
5
6
~$ env PYTHON_CONFIGURE_OPTS="--enable-shared --enable-static" pyenv install --verbose 3.10.7
~$ pip install mako
~$ git clone --recursive https://github.com/gnuradio/volk.git
~$ cd volk && mkdir build && cd build
~$ cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=/home/michael/.pyenv/versions/3.10.7/bin/python3 -DCMAKE_INSTALL_PREFIX=$HOME/.local ../
~$ make -j10 && make install

支持UHD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
~$ git clone https://github.com/EttusResearch/uhd.git
~$ cd uhd/host && mkdir build && cd build

~$ cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=OFF -DENABLE_TESTS=OFF -DENABLE_DOXYGEN=OFF -DCMAKE_INSTALL_PREFIX=$HOME/.local ../
[...]
-- ######################################################
-- # UHD enabled components
-- ######################################################
-- * LibUHD
-- * LibUHD - C API
-- * LibUHD - Python API
-- * Examples
-- * Utils
-- * Tests
-- * USB
-- * B100
-- * B200
-- * USRP1
-- * USRP2
-- * X300
-- * MPMD
-- * SIM
-- * N300
-- * N320
-- * E320
-- * E300
-- * X400
-- * OctoClock
-- * Manual
-- * API/Doxygen
-- * Man Pages
--
-- ######################################################
-- # UHD disabled components
-- ######################################################
-- * DPDK
--
-- ******************************************************
-- * You are building the UHD development master branch.
-- * For production code, we recommend our stable,
-- * releases or using the release branch (maint).
-- ******************************************************
-- Building version: 4.3.0.0-6-g5aa6bc44
-- Using install prefix: /home/michael/.local
-- Configuring done
-- Generating done

  • SoapySDR
1
2
3
4
~$ git clone https://github.com/pothosware/SoapySDR
~$ cd SoapySDR && mkdir build && cd build
~$ cmake -DCMAKE_BUILD_TYPE=Release -DPYTHON_EXECUTABLE=/home/michael/.pyenv/versions/3.10.7/bin/python -DCMAKE_INSTALL_PREFIX=$HOME/.local ../
~$ make -j 10 && make install
  • boost_1.69
1
2
3
4
~$ wget -c https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.bz2
~$ tar xvf boost_1_80_0.tar.bz2 && cd boost_1_80_0
~$ ./bootstrap.sh --prefix=${HOME}/.local
~$ ./b2 && b2 install