目录
设计模式(Design pattern):
智能家居功能细节拆分
面向对象类和对象的概念
结构体新玩法
工厂模式
1. 工厂模式的概念
2. 工厂模式的实现
智能家居项目框架设计
1. 智能家居架构代码文件工程建立
2. 主流程设计和浴室灯框架编写
基于设备控制工厂—实现灯,火灾
基于指令工厂—语音识别,Socket客户端
主程序初步编写: 实现语音和网络线程
人脸识别、车牌识别
设备安装配置 查看这篇文章 不同板子不同方法
涉及http https socket方面知识 并调用libcurll库
代码段
有23种 其中一种是工厂模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。
使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编制真正工程化。
类:是一种用户定义的引用的数据类型,也称类类型,(结构体)
对象:类的一种具象
struct Animal {
char name[128];
int age;
int sex; //成员属性
void *peat();
void *pbeat(); //成员方法
};
对象是类的一种具象,如 struct Animal dog ;struct Animal cat;struct Animal person;
dog 就是类的具体的对象,dog是Animal类的对象。
面向对象代码
#include
//类:抽象的
struct Animal {
char name[128];
int age;
int sex; //成员属性
void (*peat)();
void (*pbeat)(); //成员方法
};
void dogEat()
{
printf("狗吃骨头\n");
}
void catEat()
{
printf("猫吃鱼\n");
}
void personEat()
{
printf("人吃饭\n");
}
void dongBeat()
{
printf("咬人\n");
}
void dogBeat()
{
printf("咬人\n");
}
void catBeat()
{
printf("抓人\n");
}
void personBeat()
{
printf("打人\n");
}
int main()
{
struct Animal dog;
struct Animal cat;
struct Animal person; //对象,事物的具象
dog.peat = dogEat;
cat.peat = catEat;
person.peat = personEat;
dog.pbeat = dogBeat;//不是调用所以不用加括号 而是把这个函数名的地址赋值给这个指针地址
cat.pbeat= catBeat;
person.pbeat= personBeat;
dog.peat();//知道地址后 这里是调用
cat.peat();
person.peat();
dog.pbeat();
cat.pbeat();
person.pbeat();
return 0;
}
内核的方式给结构体赋值:
struct Animal dog2 = {
.name = "阿黄",
.peat = dogEat,
.pbeat = dogBeat
};
工厂模式(Factory Pattern)是最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(API)来指向新创建的对象
多工程用source insght写比较方便 --------------- 代码阅读器
创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(API)来指向新创建的对象。
animal.h函数 头文件
//animal头文件
#include
struct Animal{
char name[12];
int age;
char sex;
char addr[12];
void (*peat)();// 吃 函数指针
void (*pbeat)();// 打架
struct Animal *next;
};
struct Animal* putCatInLink(struct Animal* head);//添加对象 猫函数
struct Animal* putDogInLink(struct Animal* head);
struct Animal* putPersonInLink(struct Animal* head);
struct Animal* putTigerInLink(struct Animal* head);
对象函数
#include "animal.h"
void catPeat(){//猫吃什么
printf("cat eat fish\n");
}
void catPbeat(){//猫有什么动作
printf("cat miaomiao jiao\n");
}
struct Animal cat = { //结构体赋值
.name = "Tom", //cat名字
.peat = catPeat, //函数指针指向这个函数
.pbeat = catPbeat, //函数指针指向这个函数
};
struct Animal* putCatInLink(struct Animal* head)//把猫这个函数添加进对象链表 链起来
{
if(head == NULL){// 如果头为空 猫就赋值头节点 返回头节点
head = &cat; //最好定一个temp指向头节点 保证头节点不变
return head;
}
else{ //如果不为空 则头插法
cat.next = head;
head = &cat;
return head;
}
}
#include "animal.h"
void dogPeat(){//狗吃什么
printf("dog eat shit\n");
}
void dogPbeat(){//狗有什么动作
printf("dog wangwang jiao\n");
}
struct Animal dog = {
.name = "wangcai",
.peat = dogPeat,
.pbeat = dogPbeat,
};
struct Animal* putDogInLink(struct Animal* head)
{
if(head == NULL){
head = &dog;
return head;
}
else{
dog.next = head;
head = &dog;
return head;
}
}
#include "animal.h"
void personPeat(){//人吃什么
printf("person eat rice\n");
}
void personPbeat(){//人有什么动作
printf("person aa jiao\n");
}
struct Animal person = {
.name = "prppr",
.peat = personPeat,
.pbeat = personPbeat,
};
struct Animal* putPersonInLink(struct Animal* head)
{
if(head == NULL){
head = &person;
return head;
}
else{
person.next = head;
head = &person;
return head;
}
}
#include "animal.h"
void tigerPeat(){//老虎吃什么
printf("tiger eat meat\n");
}
void tigerPbeat(){//老虎有什么动作
printf("cat awuawu jiao\n");
}
struct Animal tiger = {
.name = "laohu",
.peat = tigerPeat,
.pbeat = tigerPbeat,
};
struct Animal* putTigerInLink(struct Animal* head)
{
if(head == NULL){
head = &tiger;
return head;
}
else{
tiger.next = head;
head = &tiger;
return head;
}
}
主函数
#include "animal.h"
#include
#include
struct Animal* findUtilByName(char *str,struct Animal* head)//传入名字和头节点
{
struct Animal* tmp = head;
if(tmp == NULL){//空链表 返回null
return NULL;
}
else{ //不为空 不断遍历
while(tmp != NULL){//循环遍历
if(strcmp(tmp->name,str) == 0){//找到该名字对应节点
return tmp; //返回该节点
}
tmp = tmp->next;//遍历
}
printf("input error!!\n");//没有找到
return NULL; //没找到返回 null
}
}
int main()
{
struct Animal *head = NULL;//结构体指针指向null
struct Animal *ptmp;
char buff[128] = {'\0'};
head = putCatInLink(head);//传空节点把对象链起来
head = putDogInLink(head);
head = putPersonInLink(head);
head = putTigerInLink(head);
while(1){//不断输入名字
printf("Input: cat(Tom),dog(wangcai),person(prppr),tiger(laohu)\n");
scanf("%s",buff);
ptmp = findUtilByName(buff,head);//通过结构体 把名字和头节点传过去
//找到该名字对应的节点 返回回来赋给temp指针
if(ptmp != NULL){ //找到 不为空 打印
ptmp->peat();
ptmp->pbeat();
}
memset(buff,'\0',sizeof(buff));//清空
}
return 0;
}
mainPro.c 主程序要调用这三个文件组成链表。 最后就是编写mainpro.c主函数,下面函数还编写了一个可供用户输入的然后查找响应节点的函数findUtilByName,用户输入要查找的节点名称,找到后返回指向该节点的指针,通过指针就可以对该节点进行操作,就把它当做链表的一个节点即可。
根据以上简单工厂模式,智能家居设计的时候,就可以设计为指令工厂、main函数、控制工厂,指令工厂面就存放指令(比如:语音指令、客户端指令等,将这些指令串为一个链表),控制工厂就是控制一些家庭设备(比如:各个房间的灯,门锁、串口等,创建一个链表,然后根据指令,去查找对应的控制结点),main函数里面 首先创建两个链表(指令工厂、控制工厂),然后接下来创建两个线程(一个是语音的、一个是客户端的),在每个线程里面在接受到指令后去控制工厂里面去查找对应的控制设备然后进行一系列操作。
sourceInsight
里面进行代码的编写。首先编写controlDevices.h这个头文件里面的代码,这个是设备工厂每一个结点的结构体类型,而且 还要在这个头文件里面进行函数的声明,也就是创建的那些设备.c文件里面的函数(为了将设备添加至设备链表的函数),其中这个头文件里面的结构体内容根据功能提前设定。
然后再编写 inputCommand.h这个头文件里面的内容,这个是指令工厂里面的头文件,也是指令链表里面的每一个结点的类型。编写完这两个头文件,
然后再进行设备工厂设备文件xxxx.c、指令工厂指令文件xxxx.c和mainPro.c文件的编写。
//首先编写controlDevices.h这个头文件里面的代码,这个是设备工厂每一个结点的结构体类型
#include
#include //用到外设库和打印
struct Devices{
char deviceName[128];
int pinNum;
int (*open)(int pinNum);//函数指针
int (*close)(int pinNum);
int (*deviceInit)(int pinNum);//初始化
int (*readStatus)(int pinNum);//读状态
int (*changeStatus)();//改变状态
struct Devices *next;//指向下一个结构体
};
struct Devices* addBathroomLightToDeviceLink(struct Devices* phead);
struct Devices* addUpStairLightToDeviceLink(struct Devices* phead);
struct Devices* addLivingroomLightToDeviceLink(struct Devices* phead);
struct Devices* addRestaurantLightToDeviceLink(struct Devices* phead);
struct Devices* addFireToDeviceLink(struct Devices* phead);
//===========================================================
//bathroomLight浴室灯
#include "contrlDevice.h"
int bathroomLightOpen(int pinNum)//打开
{
digitalWrite(pinNum,LOW);//初始化该引脚为高电平 不导通
}
int bathroomLightClose(int pinNum)//关闭
{
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int bathroomLightCloseInit(int pinNum)//初始化
{
pinMode(pinNum,OUTPUT);//模式为输出
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
struct Devices bathroomLight = { //定一个结构体 名叫bathroomLight
.deviceName = "bathroomLight", //结构体里面配置
.pinNum = 0, //用到哪个IO口
.open = bathroomLightOpen, //函数指针 指针指向一个函数 头文件中看是否需要配置传参
.close= bathroomLightClose, //函数指针
.deviceInit = bathroomLightCloseInit,//函数指针
.changeStatus = bathroomLightCloseStatus,//函数指针
};
//传一个这样的结构体指针过来 利用头插法插入链表中 并返回这样一个结构体指针
struct Devices* addBathroomLightToDeviceLink(struct Devices* phead)
{
if(phead == NULL){ //传过来的指针等于NULL
phead = &bathroomLight;//这个结构体赋值给头 返还
return phead;
}
else{//头节点不为空 插到头节点前面 把这个结构体赋给头并返回
bathroomLight.next = phead;
phead = &bathroomLight; //该点为头节点
return phead; //返回头节点
}
}
//=====================================
#include "contrlDevice.h"
//二楼灯
int upStairLightOpen(int pinNum)//打开
{
digitalWrite(pinNum,LOW);//初始化该引脚为高电平 不导通
}
int upStairLightClose(int pinNum)//关闭
{
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int upStairLightCloseInit(int pinNum)//初始化
{
pinMode(pinNum,OUTPUT);//模式为输出
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int upStairLightCloseStatus()//还乇兆刺?
{
}
struct Devices upStairLight = {
.deviceName = "upStairLight",
.pinNum = 1,
.open = upStairLightOpen,
.close= upStairLightClose,
.deviceInit = upStairLightCloseInit,
.changeStatus = upStairLightCloseStatus,
};
struct Devices* addUpStairLightToDeviceLink(struct Devices* phead)
{
if(phead == NULL){
phead = &upStairLight;
return phead;
}
else{
upStairLight.next = phead;//链降酵方诘闱懊?
phead = &upStairLight; //该点为头节点
return phead; //返回头节点
}
}
//================================
#include "contrlDevice.h"
//客厅灯
int livingroomLightOpen(int pinNum)//打开
{
digitalWrite(pinNum,LOW);//初始化该引脚为高电平 不导通
}
int livingroomLightClose(int pinNum)//关闭
{
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int livingroomLightCloseInit(int pinNum)//初始化
{
pinMode(pinNum,OUTPUT);//模式为输出
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
struct Devices livingroomLight = {
.deviceName = "livingroomLight",
.pinNum = 2,
.open = livingroomLightOpen,
.close= livingroomLightClose,
.deviceInit = livingroomLightCloseInit,
.changeStatus = livingroomLightCloseStatus,
};
struct Devices* addLivingroomLightToDeviceLink(struct Devices* phead)
{
if(phead == NULL){
phead = &livingroomLight;
return phead;
}
else{
livingroomLight.next = phead;//链降酵方诘闱懊?
phead = &livingroomLight; //该点为头节点
return phead; //返回头节点
}
}
//================
#include "contrlDevice.h"
//餐厅灯
int restaurantLightOpen(int pinNum)//打开
{
digitalWrite(pinNum,LOW);//初始化该引脚为高电平 不导通
}
int restaurantLightClose(int pinNum)//关闭
{
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int restaurantLightCloseInit(int pinNum)//初始化
{
pinMode(pinNum,OUTPUT);//模式为输出
digitalWrite(pinNum,HIGH);//初始化该引脚为高电平 不导通
}
int restaurantLightCloseStatus()//还乇兆刺?
{
}
struct Devices restaurantLight = {
.deviceName = "restaurantLight",
.pinNum = 5,
.open = restaurantLightOpen,
.close= restaurantLightClose,
.deviceInit = restaurantLightCloseInit,
.changeStatus = restaurantLightCloseStatus,
};
struct Devices* addRestaurantLightToDeviceLink(struct Devices* phead)
{
if(phead == NULL){
phead = &restaurantLight;
return phead;
}
else{
restaurantLight.next = phead;//链降酵方诘闱懊?
phead = &restaurantLight; //该点为头节点
return phead; //返回头节点
}
}
//======================
#include "contrlDevice.h"
//火灾报警器
int fireStatusRead(int pinNum)//读取火灾数据
{
return digitalRead(pinNum);//读取数据并返回
}
int readInit(int pinNum)//初始化
{
pinMode(pinNum,INPUT);//模式为输入
digitalWrite(pinNum, HIGH);//初始化 给火灾写入高电平不触发
}
struct Devices fire = {
.deviceName = "fire",
.pinNum = 7,
.deviceInit = readInit,
.readStatus = fireStatusRead,
};
struct Devices* addFireToDeviceLink(struct Devices* phead)
{
if(phead == NULL){
phead = &fire;
return phead;
}
else{
fire.next = phead;//链降酵方诘闱懊?
phead = &fire; //该点为头节点
return phead; //返回头节点
}
}
fire.c文件代码,代码框架和浴室灯代码框架相同,不同的是这个文件里面要有读取引脚状态的函数,同时引脚也要设置为输入模式,当检测到或火灾是火灾传感器的引脚会被拉为低电平。
火灾检测和上面的灯的设计模式一样。实现方式也是大同小异,在初始化时不同的是设计INPUT输入引脚,在火灾检测里返回状态,这里是和灯不同的点。
最后mainPro.c主程序控制代码编写,main函数里面涉及到设备工厂、设备控制工厂头结点的插入和设备文件、设备文件插入到设备链表。
声音识别的串口读取功能
inputCommand.h
是指令工厂头文件代码,里面有设备链表每一个结点的结构体类型的声明,和设备控制工厂头文件类似。 #include
#include
struct InputCommander
{
char commandName[128]; //指令名
char deviceName[128]; //设备名
char command[32]; //存放指令内容
int (*Init)(struct InputCommander *voicer , char *ipAdress, char *port); //初始化(串口)信息 建立套接字等
int (*getCommand)(struct InputCommander *voicer);
char log[1024]; //日志信息
int fd; //文件描述符
struct InputCommander *next; //链表指针
}
语音模块无非就是串口通信,忘记点这里回顾串口自己配置的serialTool.c serialTool.h全志 01 orangePi 环境搭建基础外设库的使用wiringPi_prppr_的博客-CSDN博客回顾串口。
声音相关的读取代码,无非就是串口相关的操作
语音相关的读取代码,这个文件里面的函数就要添加读取指令函数和初始化函数,所谓的初始化函数就是将串口打开然后设置相应的波特率,读取指令函数需要注意的是在读取指令前需要将缓存区初始化防止有乱码,读指令函数主要调用read函数进行指令的读取,在没有指令到来的时候,输出读取时间超时,其实代码框架和设备工厂的框架基本类似,只是文件里面包含的函数有所差异,但都有一个设备结点插入函数。
//指令工厂头文件
#include
#include
#include
#include
#include
#include
#include
struct inputCommander{
char commanName[128];
char deviceName[128];
int baud;//波特率
int fd;
char commander[64];
char port[12];//服务器端口号
char ipAddres[20];//服务器ip地址
int s_fd;//服务器返回值
int (*init)(struct inputCommander* deviceName,char* ipAddrss,char* port);
int (*getCommander)(struct inputCommander *device);
char log[1024];//日志
struct inputCommander *next;
};
struct inputCommander* addVoiceContrlToCommanderLink(struct inputCommander* phead);
struct inputCommander* addSocketToCommanderLink(struct inputCommander* phead);
//============================串口语音 指令
#include "inputCommander.h"
int voiceInit(struct inputCommander *voiceContrl,char* ipAddrss,char* port)
{ //初始化调用 主函数传入结构体 去打开这个结构体串口号和波特率 把fd放到结构体的fd里
int fd;
if((fd = myserialOpen(voiceContrl->deviceName,voiceContrl->baud)) == -1){//--3--调用serialTool.h中的函数 打开并判断是否正确
printf("myserialOpen error!!");
exit(-1);
}
else{
voiceContrl->fd = fd;//fd赋值给结构体
return fd; //返回fd
}
}
//根据主函数初始化成功 传入这个结构体用read获取命令 存放在这个结构体的commander中
int voiceGetCommander(struct inputCommander *voiceContrl)//获取指令 根据fd读取内容到commander里面
{
int nread = 0;
nread = read(voiceContrl->fd,voiceContrl->commander,sizeof(voiceContrl->commander));
if(nread != 0){
printf("voice serial get:%d,%s\n",nread,voiceContrl->commander);
}
//每次读取完清空
memset(voiceContrl->commander,'\0',sizeof(voiceContrl->commander));
return nread;
}
struct inputCommander voiceContrl = {//声音结构体
.commanName = "voice", //指令名字
.deviceName = "/dev/ttyS5", //设备名字 硬件地址
.baud = 115200, //波特率
.commander = {'\0'}, //用于存放指令
.init = voiceInit,//函数指针 初始化函数 打开返回fd方便后面使用
.getCommander = voiceGetCommander, //函数指针 指向这个函数 获取指令
.log = {'\0'}, //日志
.next = NULL, //指向下一个节点指针
};
//通过这个函数传入这个结构体指针把声音指令链起来 头插法 并返回这个结构体指针
struct inputCommander* addVoiceContrlToCommanderLink(struct inputCommander* phead)
{
if(phead == NULL){
phead = &voiceContrl;
return phead;
}
else{
voiceContrl.next = phead;//链降酵方诘闱懊?
phead = &voiceContrl; //该点为头节点
return phead; //返回头节点
}
}
//socket指令
#include "inputCommander.h"
int socketInit(struct inputCommander *socketContrl,char* ipAddrss,char* port)
{//初始化 socket连接 bind绑定端口ip listen监听并保存s_fd
int s_fd;
int bind_fd;
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
printf("socket failer!!\n");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(socketContrl->port));
inet_aton(socketContrl->ipAddres,&s_addr.sin_addr);
bind_fd = bind(s_fd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in));
if(bind_fd == -1){
printf("bind failer!!\n");
perror("why:");
}
listen(s_fd,10);
socketContrl->s_fd = s_fd;
return s_fd;
}
int socketGetCommander(struct inputCommander *socketContrl)//获取指令 根据fd读取内容到commander里面
{//初始化完连接 根据s_Fd 和c濉c_addrs相同ip和端口号连接 并根据c_fd 读取 存放再结构体指令中
int c_fd;
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
int c_addrLen = sizeof(struct sockaddr_in);
c_fd = accept(socketContrl->s_fd,(struct sockaddr*)&c_addr,&c_addrLen);
if(c_fd == -1){
printf("accept failer!!\n");
exit(-1);
}
printf("accept succeed ip:%s\n",inet_ntoa(c_addr.sin_addr));
return c_fd;
}
struct inputCommander socketContrl = {//socket服务器结构体
.commanName = "socketSever", //指令名字 没有设备号
.port = "8884", //端口号
.ipAddres = "192.168.1.3", //ip
.commander = {'\0'}, //存放指令数组
.init = socketInit,//函数指针 初始化函数 打开返回fd方便后面使用
.getCommander = socketGetCommander,//函数指针
.log = {'\0'},
.next = NULL,
};
struct inputCommander* addSocketToCommanderLink(struct inputCommander* phead)
{
if(phead == NULL){
phead = &socketContrl;
return phead;
}
else{
socketContrl.next = phead;//链降酵方诘闱懊?
phead = &socketContrl; //该点为头节点
return phead; //返回头节点
}
}
下面是语音指令输入文件代码,这个文件里面的函数就要添加读取指令函数和初始化函数,所谓的初始化函数就是将串口打开然后设置相应的波特率,读取指令函数需要注意的是在读取指令前需要将缓存区初始化防止有乱码,读指令函数主要调用read函数进行指令的读取,在没有指令到来的时候,输出:usart for voice read over time,其实代码框架和设备工厂的框架基本类似,只是文件里面包含的函数有所差异,但都有一个设备结点插入函数。
#include "contrlDevice.h"
#include "inputCommander.h"
#include
#include
#include
#include
#include
struct Devices* devicePhead = NULL;//头节点指向NULL
struct inputCommander* commanderPhead = NULL;//头节点指向NULL
struct inputCommander* socketHandle = NULL;//根据名字找到 返回回来存放在socketHandle
int c_fd;
//寻找设备工厂 通过结构体中的名字找到该节点并返回给
struct Devices* findUtilByDeviceName(char *deviceName,struct Devices* phead)
{
struct Devices* tmp = phead;
if(phead == NULL){
return NULL;
}
else{
while(tmp != NULL){
if(strcmp(tmp->deviceName,deviceName) == 0){
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
}
//寻找指令工厂 通过结构体中的名字找到该节点并返回给
struct inputCommander* findUtilByCommderName(char *commderName,struct inputCommander* phead)
{
struct inputCommander* tmp = phead;
if(phead == NULL){
return NULL;
}
else{
while(tmp != NULL){
if(strcmp(tmp->commanName,commderName) == 0){
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
}
void *voicePthreadHander()//语音线程
{
int voiceInit_fd;
int n_read = 0;
struct inputCommander* voiceHandle = NULL;
voiceHandle = findUtilByCommderName("voice",commanderPhead);//在链表中找到名为voice的把整个结构体传回来
if(voiceHandle == NULL){ //传过来空
printf("not find voice!!\n");
pthread_exit(NULL);
}else{ //传过来不为NULL
voiceInit_fd = voiceHandle->init(voiceHandle,NULL,NULL);//对声音结构体初始化并传参数过去
if(voiceInit_fd < 0){//串口打开失败
printf("uart open faile\n");
pthread_exit(NULL);
}else{
printf("uart init succeed!!\n");//打开串口成功 读取数据 并返回读取个数
while(1){
n_read = voiceHandle->getCommander(voiceHandle);
//获取完指令在voiceGetCommander中打印 因为传的是形参
}
}
}
}
//线程 通过全局变量c_fd和结构体socketHandle找到相关信息 多线程不要传参数
void readPthreadHander()
{
int n_read;
while(1){
n_read = read(c_fd,socketHandle->commander,sizeof(socketHandle->commander));
if(n_read < 0){
perror("read");
}else if(n_read > 0){
printf("socket read:%d %s\n",n_read,socketHandle->commander);
}else{
printf("clent quit!!\n");
}
memset(socketHandle->commander,'\0',sizeof(socketHandle->commander));
}
}
void *socketPthreadHander()//socket处理线程
{
int socket_fd;
pthread_t readPthread;
socketHandle = findUtilByCommderName("socketSever",commanderPhead);//在链表中找到名为voice的把整个结构体传回来
if(socketHandle == NULL){ //传过来空
printf("not find socket!!\n");
pthread_exit(NULL);
} //传过来不为NULL
socket_fd = socketHandle->init(socketHandle,NULL,NULL);//对socket初始化并把这个结构体传过去 返回s_fd
if(socket_fd > -1){//s_fd > -1 初始化成功
printf("socket init succeed!!\n");
while(1){//不断连接 并创建新线程读取内容
c_fd = socketHandle->getCommander(socketHandle);
pthread_create(&readPthread,NULL,(void*)readPthreadHander,NULL);//socket线程
//线程 通过全局变量c_fd和结构体socketHandle找到相关信息 多线程不要传参数
}
}
}
int main()
{
char deviceName[32] = {'\0'};//存放灯名字
struct Devices* ptmp = NULL;//空指针用于指向找到的对象 然后再init和open
if(wiringPiSetup() == -1){//外设库初始化
printf("wiringPiSetup faile!!\n");
exit(-1);
}
pthread_t voice_pthread;
pthread_t socket_pthread;
//指令工厂初始化
commanderPhead = addVoiceContrlToCommanderLink(commanderPhead);
commanderPhead = addSocketToCommanderLink(commanderPhead);
//设备工厂初始化
devicePhead = addBathroomLightToDeviceLink(devicePhead);//工厂链起来
devicePhead = addUpStairLightToDeviceLink(devicePhead);
devicePhead = addLivingroomLightToDeviceLink(devicePhead);
devicePhead = addRestaurantLightToDeviceLink(devicePhead);//灯
devicePhead = addFireToDeviceLink(devicePhead);//火灾
//线程池建立 语音、socket、摄像头、火灾线程
pthread_create(&voice_pthread,NULL,(void*)voicePthreadHander,NULL);//语音线程
pthread_create(&socket_pthread,NULL,(void*)socketPthreadHander,NULL);//socket线程
pthread_join(voice_pthread,NULL);
pthread_join(socket_pthread,NULL);
return 0;
}
香橙派Orange Pi Zero2开发板使用USB摄像头的方法(Linux镜像)_H('ω')M的博客-CSDN博客
01 OSI网络模型 + TCP三次握手、四次挥手 + Socket、TCP、HTTP三者之间的区别和原理_prppr_的博客-CSDN博客
02 http https和libcurl库_prppr_的博客-CSDN博客
人脸设备和车牌识别严格按照翔云平台
可能需要设置环境变量 看libcurl库安装在哪里 gcc demo5.c -lcurl -o new
https://www.cnblogs.com/xietianjiao/p/13260021.html 参考连接 里面有下载libcurl地址
libcurl的下载编译 配置 编译时链上libcurl库 设置环境变量
libcurl简介:
libcurl是一个跨平台的网络协议库,支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传, HTTP基本表单上传,代理,cookies,和用户认证。这种库使用的时候就像使用wiringPi库一样,编写完代码需要链接这个库,所以要先下载这个库。 可能要下载对应安装包
卷曲 - 下载 (curl.se) 下载源码通用 二进制的不用编译 要下载linux
下载 -》解压-》读README没有数据进入docs查看 INSTALL
步骤 ./configure --prefix=$pwd ------安装脚本到prefix路径
make -------这是一个常用的命令,用于根据 Makefile 文件进行编译。
make install:在完成编译后,如果您想将软件包安装到系统中,
libcurl下载安装方法二
通过源码网站下载 : curl - Download
或者通过git下载 git clone https://github.com/curl/curl.git (下载git指令 :sudo apt install git)
步骤 ./configure --prefix=$pwd ------安装脚本到prefix路径
make -------这是一个常用的命令,用于根据 Makefile 文件进行编译。
make install:在完成编译后,如果您想将软件包安装到系统中,
参考博文 https://www.cnblogs.com/xietianjiao/p/13260021.html
GET部分
调用curl_global_init()初始化libcurl //可以不用配置 默认
调用curl_easy_init()函数得到 easy interface型指针
调用curl_easy_setopt()设置传输选项
根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务
调用curl_easy_perform()函数完成传输任务
调用curl_easy_cleanup()释放内存
CURLOPT_WRITEFUNCTION
和 CURLOPT_WRITEDATA
,你可以定义一个回调函数来处理接收到的数据。这对选项主要用于接收数据的处理和保存,例如下载文件。CURLOPT_HEADERFUNCTION
和 CURLOPT_HEADERDATA
,你可以定义一个回调函数来处理接收到的 HTTP 头部数据。这对选项主要用于处理头部信息。CURLOPT_READFUNCTION
和 CURLOPT_READDATA
,你可以定义一个回调函数来提供要发送的数据。这对选项主要用于发送数据给远程主机。//通过get 把连接上网页后获取的内容打印出来
#include
#include
#include
#define true 1
#define false 0
typedef unsigned int bool; //注意typedef定义已有内心有分号 #define
//通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理连接上网络后返回的数据 ptr数据缓冲区
void readDataCallback( void *ptr, size_t size, size_t nmemb, void *stream)
{ //ptrptr:指向接收到的数据缓冲区的指针。
//size:每个数据块的大小(以字节为单位)。
//nmemb:接收到的数据块数目。
char readBuf[1024];
strncpy(readBuf,ptr,1024); //多个拷贝用strncpy
printf("-------get data--------\n");
printf("%s\n",readBuf);
}
bool getUrl()
{
CURL *curl;
CURLcode res;
FILE *fp;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: Agent-007");
curl = curl_easy_init(); // 1 初始化----------
if (curl)
{
// 2 配置 类似socket的bind
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 改协议头
curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
// 3 通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理readDataCallback回调
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readDataCallback);
res = curl_easy_perform(curl); // 3 执行
if (res != 0) {
curl_slist_free_all(headers);
curl_easy_cleanup(curl); // 4 断开
}
return true;
}
}
int main()
{
getUrl();
}
上传两张图片对比
// 人脸识别
//通过https连接前检查是否正确安装可用的 openssl----
#include
#include
#include
#include
#include
#include
#include
#include
#define true 1
#define false 0
typedef unsigned int bool;
char readBuf[1024];//全局变量 存放 连上网页返回回来的内容 在主函数中strstr找到“是” 则成功
//通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理连接上网络后返回的数据 ptr数据缓冲区
void readDataCallback( void *ptr, size_t size, size_t nmemb, void *stream)
{ //ptrptr:指向接收到的数据缓冲区的指针。
//size:每个数据块的大小(以字节为单位)。
//nmemb:接收到的数据块数目。
strncpy(readBuf,ptr,1024); //多个拷贝用strncpy
printf("-------get data--------\n");
printf("%s\n",readBuf);
}
char *getBase64File(char *jpgPath)//把图片传过来 base64解析后传把地址传回去
{
char cmd[256] = {'\0'};//存放品接的指令
sprintf(cmd,"base64 %s > jpgFile",jpgPath);
system(cmd); //执行 把图片转换成base64存放在jpgFile里面
int fd = open("./jpgFile",O_RDWR,0600);//打开这个jpgFile
int fileLen = lseek(fd,0,SEEK_END);//计算大小
lseek(fd,0,SEEK_SET); //光标偏移到头
char *jpgMsg = (char*)malloc(fileLen + 8);//指针开辟空间
memset(jpgMsg,'\0',fileLen +8);
read(fd,jpgMsg,fileLen);//把jpgFile里面的内容读到指针指向的空间去
close(fd);
system("rm -f jpgFile");//读完后删除这个文件
return jpgMsg;//把这个内容通过地址传回去
}
bool postUrl()
{
CURL *curl;
CURLcode res;
char *postFile;
char img1[12];//严格按照官网要求格式
char img2[12];//存放图片
char *key = "自己的key";
char *secret = "自己的";
int typeid = 21;//人脸识别的是21
char *format = "xml";
char *jpg1 = getBase64File("./liushishi.jpg");//把图片传过去转换成base64后传回来
char *jpg2 = getBase64File("./liushishi2.jpg");
int len = strlen(key)+strlen(secret)+strlen(jpg1)+strlen(jpg2) + 128;//开辟空间存
postFile = (char *)malloc(len);//开辟怎么大的空间 用于拼接内容
memset(postFile,'\0',len);
sprintf(postFile,"&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",jpg1,jpg2,key,secret,21,format);//把图片的内容拼接起来放在postFile中
// 1
curl = curl_easy_init();// 1--------------初始化
if (curl)
{
// 2 -------要通过https连接的网页接口地址: // 指定url
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do");
//指定post接口调用方法:
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,postFile); // 指定post内容
// 3 通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理readDataCallback回调
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readDataCallback);
// 4 -------调用curl_easy_perform()函数完成传输任务
res = curl_easy_perform(curl);
printf("OK res = %d\n",res);
//通过判断返回的内容中是否有关键字 判断是否成功
if(strstr(readBuf,"是") != NULL){
printf("connect succeed!!!\n");
}else{
printf("connect faile!!!\n");
}
}
// 5 ----- 清除这个连接释放内存
curl_easy_cleanup(curl);
return true;
}
int main(void)
{
postUrl();
}
车牌识别
//通过https连接前检查是否正确安装可用的 openssl----
#include
#include
#include
#include
#include
#include
#include
#include
#define true 1
#define false 0
typedef unsigned int bool;
char readBuf[1024];//全局变量 存放 连上网页返回回来的内容 在主函数中strstr找到“是” 则成功
//通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理连接上网络后返回的数据 ptr数据缓冲区
void readDataCallback( void *ptr, size_t size, size_t nmemb, void *stream)
{ //ptrptr:指向接收到的数据缓冲区的指针。
//size:每个数据块的大小(以字节为单位)。
//nmemb:接收到的数据块数目。
strncpy(readBuf,ptr,1024); //多个拷贝用strncpy
printf("-------get data--------\n");
printf("%s\n",readBuf);
}
char *getBase64File(char *jpgPath)//把图片传过来 base64解析后传把地址传回去
{
char cmd[256] = {'\0'};//存放品接的指令
sprintf(cmd,"base64 %s > jpgFile",jpgPath);
system(cmd); //执行 把图片转换成base64存放在jpgFile里面
int fd = open("./jpgFile",O_RDWR,0600);//打开这个jpgFile
int fileLen = lseek(fd,0,SEEK_END);//计算大小
lseek(fd,0,SEEK_SET); //光标偏移到头
char *jpgMsg = (char*)malloc(fileLen + 8);//指针开辟空间
memset(jpgMsg,'\0',fileLen +8);
read(fd,jpgMsg,fileLen);//把jpgFile里面的内容读到指针指向的空间去
close(fd);
system("rm -f jpgFile");//读完后删除这个文件
return jpgMsg;//把这个内容通过地址传回去
}
bool postUrl()
{
CURL *curl;
CURLcode res;
char *postFile;
char img[12];
char *key = "JJnPE3cNoXajrjf5RYE6KE";
char *secret = "3c29ef4eba12408791765a429170d948";
int typeid = 19;
char *format = "xml";
char *carImg = getBase64File("./car.jpg");
int len = strlen(key)+strlen(secret)+strlen(carImg) + 64;
postFile = (char *)malloc(len);
memset(postFile,'\0',len);
sprintf(postFile,"&img=%s&key=%s&secret=%s&typeId=%d&format=%s",carImg,key,secret,19,format);
// 1
curl = curl_easy_init();
if (curl)
{
// 2
curl_easy_setopt(curl, CURLOPT_URL,"https://netocr.com/api/recogliu.do"); // 指定url
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,postFile); // 指定post内容
// 3 通过配置CURLOPT_WRITEFUNCTION 使用回调函数存放处理readDataCallback回调
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,readDataCallback);
// 4
res = curl_easy_perform(curl);
printf("OK res = %d\n",res);
// if(strstr(readBuf,"是") != NULL){
// printf("connect succeed!!!\n");
// }else{
// printf("connect faile!!!\n");
// }
}
curl_easy_cleanup(curl);
return true;
}
int main(void)
{
postUrl();
}