智能家居2 -- 实现网络控制模块

这一模块的思路和前面的语言控制模块很相似,差别只是调用TCP 去控制

废话少说,放码过来

增添/修改代码

socket_interface.c


#if 0
struct control
{
char control_name[128]; //监听模块名称
int (*init)(void); //初始化函数
void (*final)(void);//结束释放函数
void *(*get)(void *arg);//监听函数,如语音监听
void *(*set)(void *arg); //设置函数,如语音播报
struct control *next;
};
#endif

#include <pthread.h>
#include <stdio.h>
#include "voice_interface.h"
#include "mq_queue.h"
#include "uartTool.h"
#include "global.h"


static int serial_fd = -1; // static 这个 变量只在当前文件有效

static int voice_init(void )
{
  serial_fd = myserialOpen(SERIAL_DEV,BAUD); // 初始化并且打开串口
  printf("%s|%s|%d   serial_fd = %d\n",__FILE__,__func__,__LINE__,serial_fd);

  return serial_fd;
}

static void voice_final(void)
{
  if(-1 != serial_fd) // 打开串口成功
  {
    close(serial_fd); // 关闭我们打开的串口
    serial_fd = -1; // 复位
  }
}
// 接收语言指令
static void* voice_get(void *arg)// mqd 通过arg 传参获得
{
    int len = 0;
    mqd_t mqd = -1;
    ctrl_info_t * ctrl_info = NULL; 
    if(NULL != arg)
        ctrl_info = (ctrl_info_t*)arg;

    unsigned char buffer[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 初始化 buffer
    if (-1 == serial_fd)
    {
        //打开串口
        serial_fd = voice_init();// 尝试打开串口
        if (-1 == serial_fd){ //还是打开失败
        printf("%s | %s | %d:open serial failed\n", __FILE__, __func__, __LINE__); // 三个宏的含义: 文件名 - main.c,函数名 - pget_voice ,行号 -  138
        pthread_exit(0);   
        }                                                        // 串口打开失败 -->退出
    }
 
     
    mqd = ctrl_info->mqd; 
    

    if((mqd_t)-1 == mqd)
    {
       pthread_exit(0);  
    }

    pthread_detach(pthread_self());// 与父线程分离
    printf("%s thread start\n",__func__);

    while (1)
    {
        len = serialGetstring(serial_fd, buffer); // 通过串口获得语言输入
        printf("%s|%s|%d,  0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
        printf("%s|%s|%d:len = %d\n",__FILE__,__func__,__LINE__,len);
        if (len > 0)         // 判断是否 接到识别指令
        {
          if(buffer[0] == 0xAA && buffer[1] == 0x55 
            &&buffer[4]==0x55 && buffer[5]==0xAA)
            {
               printf("%s|%s|%d, send: 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
        
              send_msg(mqd,buffer,len); // 注意获取len长度不能使用strlen() --> 0x00 会识别为截止位-->只能读取到三个字节(但不是我们实际的截止位(0x55 0xAA ))
            }
            memset(buffer,0,sizeof(buffer)); // 复位buffer
        }
    }

    pthread_exit(0);

}

static void* voice_set(void *arg)
{

}

struct  control voice_control ={
    .control_name = "voice",
    .init = voice_init,
    .final = voice_final,
    .get = voice_get,
    .set = voice_set,
    .next = NULL
};


struct control *add_voice_to_ctrl_list(struct control *phead)
{
  //头插法实现 添加链表节点
  struct control *pnew = NULL;
 
  
  if(NULL == phead)
  {
    phead = &voice_control; // 直接传入我们的 voice_control
  }

  else// 头结点非空 - 链表有数据
  {
   voice_control.next = phead; //把新的节点的next指向头结点
   phead = &voice_control; // 让心节点成为头结点
  }

  return phead;

};



socket_interface.h

#ifndef ___SOCKET_INTERFACE_H___
#define ___SOCKET_INTERFACE_H___

#include "control.h"
struct control *add_tcpsocket_to_ctrl_list(struct control *phead);



#endif

修改的main.c

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

#include "control.h"
#include "mq_queue.h"
#include "voice_interface.h"
#include "socket_interface.h"
#include "global.h"

// msg_queue_create



int main() {
    pthread_t thread_id;
    struct control *control_phead = NULL;
    struct control *pointer = NULL;
    ctrl_info_t *ctrl_info = NULL;
    ctrl_info = (ctrl_info_t *)malloc(sizeof(ctrl_info_t));
    ctrl_info->ctrl_phead = NULL;
    ctrl_info->mqd = -1;

    int node_num = 0; // 统计节点数

    // 创建消息队列
    ctrl_info->mqd = msg_queue_create();
    if(-1 == ctrl_info->mqd)// 创建消息队列失败
    {
        printf("%s|%s|%d, mqd= %d\n",__FILE__,__func__,__LINE__,ctrl_info->mqd);
        return -1;
    }
    
    ctrl_info->ctrl_phead = add_voice_to_ctrl_list(ctrl_info->ctrl_phead);
    ctrl_info->ctrl_phead = add_tcpsocket_to_ctrl_list(ctrl_info->ctrl_phead);
    //ctrl_info->ctrl_phead = add_fire_to_ctrl_list(ctrl_info->ctrl_phead);
  

    pointer = ctrl_info->ctrl_phead;

    while(NULL!=pointer) // 对所有控制结构体初始化,并且统计节点数
    {
        if(NULL != pointer->init)
        {
             printf("%s|%s|%d   control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
             pointer->init();
        }
        pointer = pointer->next;
        node_num++; // 统计节点数
    }

    // 根据节点的总数 --> 创建对应数目的线程
    pthread_t *tid = (pthread_t *)malloc(sizeof(int) *node_num);
    pointer = ctrl_info->ctrl_phead;

    for(int i=0;i<node_num;++i)//遍历所有节点
    {
       if(NULL != pointer->get){
          printf("%s|%s|%d   control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
          pthread_create(&tid[i],NULL,(void *)pointer->get,(void *)ctrl_info); // 传入这个结构体参数,方便同时调用多组线程里面的API
       }
        pointer = pointer->next;
    }
    
     for(int i=0;i<node_num;++i)
     {
     pthread_join(tid[i],NULL);
     }

     for(int i=0;i<node_num;++i)
     {
      if(NULL != pointer->final)
          pointer->final(); // 接打开的使用接口关闭
      pointer = pointer->next;
     }

     msq_queue_final(ctrl_info->mqd);

}

编译执行:

编译:

make

发送到arm-64平台

scp ./obj/smarthome  orangepi@192.168.1.11:/home/orangepi

执行:

sudo -E ./smarthome

/遇到如下报错 -- 解决:


scp: /home/orangepi/smarthome: Text file busy

kill -9 进程即可

 kill之后成功了

bind: Address already in use
 

要解决这个问题,您可以尝试以下步骤:

  1. 查找并关闭现有进程:使用 netstatlsof 或 ss 命令来查找正在监听该端口的进程,并关闭它。

    
    
    sudo netstat -tulnp | grep [端口号] 
    # 或者 
    sudo lsof -i :[端口号] 
    # 或者 
    sudo ss -tulnp | grep [端口号]
     

    找到进程ID(PID)后,使用 kill -9 命令来结束该进程。

  2. 重启计算机:如果无法确定哪个进程正在使用端口,或者无法结束该进程,您可以考虑重启计算机。

  3. 使用不同的端口:如果您只是想要快速测试您的应用程序,并且不关心特定的端口号,您可以尝试使用另一个端口。

TCP验证:

(注意发送格式 16进制)

否则你发送的数据很可能变成这样

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值