准备工作(支付宝沙盒信息获取)
登录 开发者中心控制台 (alipay.com) 使用支付宝进行登录。
进入沙箱环境 开放平台-沙箱环境 (alipay.com)
如果《RSA2密钥(公钥模式) 》的查看是灰色的,点击启用。点击查看可获取应用公钥,应用私钥和支付宝公钥。
下载并安装沙盒版的支付宝应用。通过提供的账号登录沙盒版支付宝,进行付款。
(微信个人无法申请 APPID 等信息,且没有提供沙盒平台,所以无法进行测试。提供的 JAR 包里面是有晕哥提供的 APPID 等信息,可以进行测试。提供的 java 源码已经将微信的 APPID 等信息删除)
服务器端搭建
linux 平台搭建
sudo apt install openjdk-8-jdk mosquitto
修改 D1PayServer.jar 压缩包中的 zfbinfo.properties 文件,将 appid,public_key(应用公钥),private_key(应用私钥),alipay_public_key(支付宝公钥)替换成自己支付宝沙盒提供的。
然后将 D1PayServer.jar 上传至 linux 平台运行。
java -jar D1PayServer.jar
运行效果:
客户端运行
烧写 tina_d1-nezha_uart0.img 镜像,内核已经修改为默认 HDMI 输出,分辨率为 480P(720x480)。
连接 wifi
wifi_connect_ap_test GL-MT300N-V2-0be goodlife
修改应用配置文件:
vim /bin/D1Pay/D1PayClientConfig.json
{
"device_id":"kw",
"mqtt_server_ip":"192.168.8.108",
"mqtt_sub_top":"d1_pay_client",
"mqtt_pub_top":"d1_pay_server",
"fb":"/dev/fb0",
"input":"/dev/input/event2"
}
修改 mqtt_server_ip 为自己的 mqtt 服务器的地址,input 修改为自己的触摸设配。
运行应用程序
root@TinaLinux:/# d1_pay_launche
运行效果(使用的HDMI屏幕,拥有触摸,分辨率 800x480),完成支付后将会播报语音以及控制一个 GPIO 输出 5 秒的高电平。
客户端添加一个商品信息
商品信息保存在 /bin/D1Pay/ProductList/ 目录下,每一件商品对应一个文件夹。每一个文件夹都有 Image.png ProductDescribe.txt文件,Image.png为 350x350 像素的商品图片,ProductDescribe.txt为描述文件,包含商品名,价格,付款成功后控制的 GPIO,以及商品详细介绍。
.
├── D1 Board
│ ├── Image.png
│ └── ProductDescribe.txt
├── D1 IC
│ ├── Image.png
│ └── ProductDescribe.txt
└── XR806 Board
├── Image.png
└── ProductDescribe.txt
ProductDescribe.txt 文件第一行为商品名字,第二行为价格(价格必须保留小数两位),第三(商品id)行为付款成功后控制的 GPIO(1-GPIOD11, 2-GPIO12, 3-GPIO13)。余下信息均为商品描述信息。
cat D1 Board/ProductDescribe.txt
D1 Board
599.99
1
CPU : C906 64bit RISC-V 32 KB I-cache + 32 KB D-cache
DSP :
HiFi4 DSP 600MHz
32 KB I-cache + 32 KB D-cache
64 KB I-ram + 64 KB D-ram
Memory :
DDR2/DDR3, up to 2 GB
SD3.0/eMMC 5.0, SPI Nor/Nand Flash
客户端与服务端数据交互格式
通信数据采用 json 数据,定义的数据存在多余的,部分并没有使用到
客户端发送订单信息至服务器
{
"device_id":"kw", 设备id
"msg_type":"0", 0客户端发送订单 1服务器返回收款信息至客户端 2支付成功服务器返回至客户端
"product_id":"1", 商品id 用于控制 GPIO
"product_name":"D1 IC", 商品名称
"pay_way":"0", 0支付宝 1微信
"price":"34.97" 价格
}
服务器返回生成的支付二维码信息至客户端
{
"device_id":"kw", 设备id
"msg_type":"1", 0客户端发送订单 1服务器返回收款信息至客户端 2支付成功服务器返回至客户端
"product_id":"1", 商品id 用于控制 GPIO
"pay_way":"0", 0支付宝 1微信
"return":"ok", ok err
"price":"34.97", 价格
"out_trade_no":"63827381363", 订单号
"pay_qrcode":"xxxweduwqcfgy3t72" 用于生成二维码
}
支付成功服务器返回至客户端,支付失败则不返回
{
"device_id":"kw", 设备id
"msg_type":"2", 0客户端发送订单 1服务器返回收款信息至客户端 2支付成功服务器返回至客户端
"product_id":"1", 商品id 用于控制 GPIO
"pay_way":"0", 0支付宝 1微信
"return":"ok", ok err
"price":"34.97", 价格
"out_trade_no":"63827381363" 订单号
}
服务器端工程结构
eva@ubuntu:~/Desktop/d1_pay_server_master$ tree
.
├── D1PayServer
│ ├── pom.xml
│ ├── resource
│ │ └── zfbinfo.properties
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ └── com
│ │ │ └── nuist
│ │ │ └── kw
│ │ │ └── D1PayServer
│ │ │ ├── AliPayThread.java
│ │ │ ├── App.java
│ │ │ ├── CommonUtils.java
│ │ │ ├── MyConfig.java
│ │ │ ├── OrderInformation.java
│ │ │ ├── PaymentInformation.java
│ │ │ ├── PayThread.java
│ │ │ ├── ResultInformation.java
│ │ │ └── WxPayThread.java
zfbinfo.properties 保存支付宝 APPID 等信息
App.java 初始化一个 mqtt 服务器,main 入口
MyConfig.java 微信 APPID 等信息
PayThread.java 当 mqtt 服务器收到一个订单消息,进行判断是支付宝支付,还是微信支付,然后开启相应的支付处理线程
AliPayThread.java 支付宝支付线程,负责请求支付二维码,循环判断订单支付结果,3 分钟未支付,则不再处理。
WxPayThread.java 微信支付线程,负责请求支付二维码,循环判断订单支付结果,3 分钟未支付,则不再处理。
OrderInformation.java PaymentInformation.java ResultInformation.java 负责构造通信数据字符串。
Maven 项目依赖
<!-- 微信sdk -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!-- 支付宝sdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.209.ALL</version>
</dependency>
<!-- mqtt sdk -->
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
客户端工程结构
客户端代码结构如下,app 存放的是应用代码,build 存放的是编译生成的 .o 文件以及顶层 Makefile(使用的百问网的 lvgl 移植的 Makefile),build.sh 编译脚本,lirary 存放的是库源码,Makefile 硬链接指向 build/Makefile,out 为输出的应用程序目录。
eva@ubuntu:~/Desktop/d1_pay_client$
.
├── app
│ ├── app.mk
│ ├── include
│ ├── launcher_ui.c # UI 界面
│ ├── launcher_ui.h
│ ├── lv_drv_init.c # 驱动初始化
│ ├── lv_drv_init.h
│ ├── main.c # 程序入口
│ ├── mqtt_client.c # mqtt 客户端初始化 数据处理
│ ├── mqtt_client.h
│ ├── pin_control.c # 引脚控制,增加引脚修改该文件
│ ├── pin_control.h
│ ├── play_pay_result.c # 语音播报
│ ├── play_pay_result.h
│ ├── untilities.c # 提供一些函数
│ └── untilities.h
├── build
│ └── Makefile
├── build.sh
├── lirary
├── Makefile
└── out
├── bin
├── etc
└── lib
build.sh 中指定编译工具链,通过 ./build.sh 进行编译,./build.sh clean 进行清除编译中间文件。
修改引脚修改 pin_control.c 如下部分(计算公式 32*n+i)
mosquitto编译
应用程序使用了 mosquitto 库,build.sh并不会去编译它,所以这个需要单独编译,编译完成后,将库拷贝到 out/lib 目录下。mosquitto 在 lirary 目录下,在 lirary 目录下新建一个 mosquitto-risc 目录,用于保存编译输出文件。
设置交叉编译工具链
vim ~/.bashrc
export PATH=$PATH:/home/eva/d1/D1/prebuilt/gcc/linux-x86/riscv/toolchain-thead-glibc/riscv64-glibc-gcc-thead_20200702/bin/
source ~/.bashrc
交叉编译 uuid
tar -vxf libuuid-1.0.3.tar.gz
./configure --prefix=/home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc CC=riscv64-unknown-linux-gnu-gcc --host=riscv64-unknown-linux-gnu
make && make install
交叉编译 openssl 库
tar -vxf openssl-1.0.2g.tar.gz
./config no-asm shared --prefix=/home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc
#删除Makefile中的-m64(一共有两个),修改Makefile中的
CC= riscv64-unknown-linux-gnu-gcc
AR= riscv64-unknown-linux-gnu-ar $(ARFLAGS) r
RANLIB= riscv64-unknown-linux-gnu-ranlib
NM= riscv64-unknown-linux-gnu-nm
make && make install
交叉编译 mosquitto
tar -vxf mosquitto-1.5.tar.gz
make WITH_SRV=no CC=riscv64-unknown-linux-gnu-gcc CXX=riscv64-unknown-linux-gnu-g++ CFLAGS="-I /home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc/include -I /home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc/include" LDFLAGS="-L/home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc/lib -L/home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc/lib -lssl -lcrypto -luuid"
make DESTDIR=/home/eva/Desktop/d1_pay_client/lirary/mosquitto-risc install
D1 内核配置
配置编译环境
source build/envsetup.sh
lunch d1_nezha-tina
开启 nfs
make kernel_menuconfig
File systems --->
[*] Network File Systems --->
│ │ <*> NFS client support │ │
│ │ <*> NFS client support for NFS version 2 │ │
│ │ [*] NFS client support for NFS version 3 │ │
│ │ [*] NFS client support for the NFSv3 ACL protocol extension│ │
│ │ [*] NFS client support for NFS version 4 │ │
│ │ [*] NFS client support for NFSv4.1 │ │
│ │ [*] NFS client support for NFSv4.2 │ │
│ │ (kernel.org) NFSv4.1 Implementation ID Domain │ │
│ │ [*] NFSv4.1 client support for migration │ │
│ │ [*] Use the legacy NFS DNS resolver
修改开机默认 HDMI 输出(如果开机不是默认 HDMI 输出,开机后再启动 HDMI 输出,会输出有问题)
修改 uboot 设备树文件
./D1/device/config/chips/d1/configs/nezha/uboot-board.dts
214 行
disp_init_enable = <1>;
disp_mode = <0>;
- screen0_output_type = <1>;
- screen0_output_mode = <4>;
-
- screen1_output_type = <3>;
- screen1_output_mode = <10>;
-
- screen1_output_format = <0>;
- screen1_output_bits = <0>;
- screen1_output_eotf = <4>;
- screen1_output_cs = <257>;
- screen1_output_dvi_hdmi = <2>;
- screen1_output_range = <2>;
- screen1_output_scan = <0>;
- screen1_output_aspect_ratio = <8>;
-
- dev0_output_type = <1>;
- dev0_output_mode = <4>;
+ screen0_output_type = <3>;
+ screen0_output_mode = <10>;
+
+ screen0_output_format = <0>;
+ screen0_output_bits = <0>;
+ screen0_output_eotf = <4>;
+ screen0_output_cs = <257>;
+ screen0_output_dvi_hdmi = <2>;
+ screen0_output_range = <2>;
+ screen0_output_scan = <0>;
+ screen0_output_aspect_ratio = <8>;
+
+ screen1_output_type = <1>;
+ screen1_output_mode = <4>;
+
+ dev0_output_type = <4>;
+ dev0_output_mode = <2>;
dev0_screen_id = <0>;
- dev0_do_hpd = <0>;
-
- dev1_output_type = <4>;
- dev1_output_mode = <10>;
- dev1_screen_id = <1>;
- dev1_do_hpd = <1>;
+ dev0_do_hpd = <1>;
def_output_dev = <0>;
hdmi_mode_check = <1>;
修改 linux 设备树文件
./D1/device/config/chips/d1/configs/nezha/linux-5.4/board.dts
1128 行
disp_init_enable = <1>;
disp_mode = <0>;
- screen0_output_type = <1>;
- screen0_output_mode = <4>;
-
- screen1_output_type = <3>;
- screen1_output_mode = <10>;
-
- screen1_output_format = <0>;
- screen1_output_bits = <0>;
- screen1_output_eotf = <4>;
- screen1_output_cs = <257>;
- screen1_output_dvi_hdmi = <2>;
- screen1_output_range = <2>;
- screen1_output_scan = <0>;
- screen1_output_aspect_ratio = <8>;
-
- dev0_output_type = <1>;
- dev0_output_mode = <4>;
+ screen0_output_type = <3>;
+ screen0_output_mode = <10>;
+
+ screen0_output_format = <0>;
+ screen0_output_bits = <0>;
+ screen0_output_eotf = <4>;
+ screen0_output_cs = <257>;
+ screen0_output_dvi_hdmi = <2>;
+ screen0_output_range = <2>;
+ screen0_output_scan = <0>;
+ screen0_output_aspect_ratio = <8>;
+
+ screen1_output_type = <1>;
+ screen1_output_mode = <4>;
+
+ dev0_output_type = <4>;
+ dev0_output_mode = <2>;
dev0_screen_id = <0>;
- dev0_do_hpd = <0>;
-
- dev1_output_type = <4>;
- dev1_output_mode = <10>;
- dev1_screen_id = <1>;
- dev1_do_hpd = <1>;
+ dev0_do_hpd = <1>;
def_output_dev = <0>;
hdmi_mode_check = <1>;
dev0_output_mode 为分辨率,这里设置为 480P
enum disp_tv_mode {
DISP_TV_MOD_480I = 0,
DISP_TV_MOD_576I = 1,
DISP_TV_MOD_480P = 2,
DISP_TV_MOD_576P = 3,
DISP_TV_MOD_720P_50HZ = 4,
DISP_TV_MOD_720P_60HZ = 5,
DISP_TV_MOD_1080I_50HZ = 6,
DISP_TV_MOD_1080I_60HZ = 7,
DISP_TV_MOD_1080P_24HZ = 8,
DISP_TV_MOD_1080P_50HZ = 9,
DISP_TV_MOD_1080P_60HZ = 0xa,
/***/
编译 uboot
cboot
muboot
进入顶层目录,编译其它部分
make -j8
pack
代码,固件下载
D1PayPack.zip
演示视频