年底这段时间相信大家都和我一样挺忙的,最近稍得空闲,赶紧来更新咱的 FlappyBird。
上次说到要加一个联机对战的功能,想想这个小鸟也不适合改成对战类,不过没关系,这也不妨碍咱们来研究一下开发板联网的方法。
所以本文主要介绍我是如何让开发板具备连接 wifi 并开启 socket
server,然后开发基于HarmonyOS 的手机遥控器,或者也可以说成是虚拟手柄的雏形吧。
说起来,这可是鸿蒙 OS 手机和鸿蒙 Hi3861 开发板之间的故事哦。
https://harmonyos.51cto.com/posts/1157
复制
一般来说,wifi 相关的接口都在“\vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\lwip\netifapi.h”头文件中,仔细阅读代码中的注释会很有帮助。
这次没有把手机配网功能放进来,因为觉得每次运行还得手机一顿操作好麻烦,用的是直接 STA 模式连接指定 AP 的方式,以后可以改进成碰一碰组网的方式,留待后续研究。

这是开发板启动 server 的流程图:

在启动 socket
server 后,就是接受客户端的连接请求,然后循环接收数据,根据指令执行动作。
还有一点需要注意,那就是网络相关的操作函数放到单独的一个 thread 中执行,即后台连接网络,避免阻塞程序主线程。这里 socket server 侦听端口设置为 8888。
很快我就发现,不知道开发板的 IP 地址啊。虽然我可以在路由器管理页面上查看到所有设备 IP,但总是不方便,总不能去哪都得找路由器管理员吧。
于是我又加入了一键显示 IP 地址的功能。具体就是调用 netifapi_netif_get_addr 函数(netifapi.h)。
/*
* Func Name: netifapi_netif_get_addr
*/
/**
* @ingroup Threadsafe_Network_Interfaces
*
* @brief
*
* This is a thread safe API, used to get IP_add configuration for a network interface
* (including netmask and default gateway).
* It is recommended to use this API instead of netif_get_addr()
*
* @param[in] netif Indicates the network interface to get.
* @param[in] ipaddr Indicates the IP address.
* @param[in] netmask Indicates the network mask.
* @param[in] gw Indicates the default gateway IP address.
*
* @returns
* 0 : On success \n
* Negative value : On failure \n
*
* @par Related Topics
* netif_get_addr()
*
* @note
* - netmask and/or gw can be passed NULL, if these details about the netif are not needed
*/
err_t netifapi_netif_get_addr(struct netif *netif,
ip4_addr_t *ipaddr,
ip4_addr_t *netmask,
ip4_addr_t *gw);复制
第一个参数 netif,即之前连接 wifi 用到的 netif 结构体指针,其他三个分别是用来返回的 ip 地址、子网掩码、网关。
char *ip = ip4addr_ntoa(ipAddr);
printf("ip: %s\n", ip);
free(ip)//用完记得释放复制
其实在 \vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\lwip\ip4_addr.h 头文件中定义好了一系列的转换函数。
u32_t ipaddr_addr(const char *cp);
int ip4addr_aton(const char *cp, ip4_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ip4addr_ntoa(const ip4_addr_t *addr);
char *ip4addr_ntoa_r(const ip4_addr_t *addr, char *buf, int buflen);
int inet_pton4(const char *src, unsigned char *dst);
const char *lwip_inet_ntop4(const unsigned char *src, char *dst, u32_t size);复制
手机控制器方面,我在 DevEcoStudio 中基于鸿蒙 OS 做了一版 App,主要实现 Tcp 方式连接到指定 IP,并发送指令。
但由于手上没有真机,故无法调试,只能另外做了一个 Android 版本 App 代替调试,有些遗憾,希望也能借此机会拿到 P40,完成这个梦想,也一睹鸿蒙 OS 的芳容。


就是模拟器没法联网,比较无奈。不过这不妨碍做一个 Android 版本用来测试。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//添加按钮事件回调
this.findViewById(R.id.btn_go).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
EditText editIp = findViewById(R.id.edit_ip);//界面添加了一个IP地址输入框
String ip = editIp.getText().toString();
sendCmd(ip);//向指定IP发送指令
}
}).start();
}
});
}
private Socket socket;
private void sendCmd(String ipAddr){
int port = 8888;//开发板socket server监听端口号8888
try {
if(socket == null){
socket = new Socket(ipAddr, port);//创建socket客户端
Log.i("JoyStick", "Create socket!!");
}
String cmdData = "A";//发送一个A
byte data[] = cmdData.getBytes();
socket.getOutputStream().write(data);
Log.i("JoyStick", "Send success!!");
showMessage("Send success!", Toast.LENGTH_SHORT);
}
catch (Exception e)
{
e.printStackTrace();
Log.e("JoyStick", e.toString());
showMessage("Send Error!\n" + e.toString(), Toast.LENGTH_SHORT);
}
}
}复制

这里只是发送了一种指令“A",因为 FlappyBird 只用到了一个控制按钮,如果考虑通用性的话,可以制定一套协议,实现手柄所有按键的指令发送。
例如:左 L,右 R,上 U,下 D,按键 A/B/P/Q 等,留待以后完善。
好了,编译、烧板、运行。实际操作起来,手感还是不错的,上图。
这是手机控制演示:

后续打算将一些套件没有的外设纳入进来,比如 GPS 模块,摄像头,蓝牙之类的,应该能碰撞出更多的创意火花,大家觉得如何呢?
专注开源技术,共建鸿蒙生态

点“阅读原文”下载源码