Security monitoring project—Web page controls the fan of Zigbee terminal node through A9

Article directory

  • Preface
  • 1. Zigbee CGI interface
  • 2. Request thread and hardware control
  • 3. Phenomenon display
  • Summarize

Foreword

Continuing from the previous issue, we can take a look at the previous functional design part. There is another control on the web page, which is to control the fan node on Zigbee through the web page. The workload of this part is quite large, not only to realize HTML sending control The command is received on the A9 platform, and the serial port communication of the A9 platform is required to control the zigbee coordinator, and the zigbee terminal node is controlled through the zigbee coordinator (this step is based on the debugging of the zigbee coordinator and terminal node); in the end, it is realized The web page controls the zigbee node, which also realizes wireless control!

1. Zigbee CGI interface

The first step is to look at how command words are issued:

#include <stdio.h>
#include "cgic.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define N 8
struct msg
{<!-- -->
long type;
long msgtype;
unsigned char text[N];
};
int cgiMain()
{<!-- -->
key_t key;
char buf[N];
char sto_no[2];
int msgid;
struct msg msg_buf;
memset( & amp;msg_buf,0,sizeof(msg_buf));
\t
cgiFormString("fan",buf,N);
cgiFormString("store",sto_no,2);

if((key = ftok("/tmp", 'g')) < 0)
{<!-- -->
perror("ftok");
exit(1);
}

if((msgid = msgget(key, 0666)) < 0)
{<!-- -->
perror("msgget");
exit(1);
}
bzero (msg_buf.text, sizeof (msg_buf.text));

switch (buf[0])
{<!-- -->
case '0':
{<!-- -->
msg_buf.text[0] = (0 << 6) | (2 << 4) | (0 << 0);
break;
}
case '1':
{<!-- -->
msg_buf.text[0] = (0 << 6) | (2 << 4) | (1 << 0);
break;
}
}
\t
msg_buf.type = 1L;
msg_buf.msgtype = 4L;
msgsnd(msgid, & amp;msg_buf,sizeof(msg_buf)-sizeof(long),0);

sto_no[0] -= 48;


cgiHeaderContentType("text/html\\
\\
");
fprintf(cgiOut, "<HTML><HEAD>\\
");
fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\\
");
fprintf(cgiOut, "<BODY>");

fprintf(cgiOut, "<H2>send sucess</H2>");

//fprintf(cgiOut, "<a href='.html'>return</a>");
fprintf(cgiOut, "<meta http-equiv="refresh" content="1;url=../a9_zigbee%d.html">", sto_no[0 ]);
fprintf(cgiOut, "</BODY>\\
");
fprintf(cgiOut, "</HTML>\\
");
return 0;
}

I haven’t given too many comments here. In fact, the process is basically the same as the previous LED and beep codes, and the framework structure is also the same; this is the advantage of a good framework, which makes development easier;

2. Request thread and hardware control

The request thread only needs to add the control type in the switch…case statement; the control process here is written directly in the switch, or it can be written in a separate processing thread; serial port programming under Linux is used here, so it needs Contains the header file linuxuart.h;

#include "data_global.h"
#include "linuxuart.h"

//message queue id
extern int msgid;
//ipc object key value
extern key_t key;
//Lock resources
extern pthread_mutex_t mutex_client_request,
        mutex_refresh,
        mutex_sqlite,
mutex_transfer,
mutex_analysis,
mutex_sms,
mutex_buzzer,
mutex_led,
mutex_camera;
//Condition variable
extern pthread_cond_t cond_client_request,
        cond_refresh,
        cond_sqlite,
cond_transfer,
cond_analysis,
cond_sms,
cond_buzzer,
cond_led,
cond_camera;
//Module control command word
extern unsigned char cmd_led;
extern unsigned char cmd_buzzer;
extern unsigned char cmd_fan;

//Phone number of GPRS module
extern char recive_phone[12];
extern char center_phone[12];

//Message queue communication structure
struct msg msgbuf;

void *pthread_client_request(void *arg)
{<!-- -->
if((key = ftok("/tmp",'g')) < 0){<!-- -->
perror("ftok failed .\\
");
exit(-1);
}

msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666); //Check whether there is this key value in the message queue. If so, return the corresponding -1. If not, create and return the id of the created message queue.
if(msgid == -1) {<!-- -->
if(errno == EEXIST){<!-- --> //If already exists
msgid = msgget(key,0777); //Set permissions to 0777
}else{<!-- -->
perror("fail to msgget");
exit(1);
}
}
printf("pthread_client_request\\
");
\t
while(1){<!-- -->
bzero( & amp;msgbuf,sizeof(msgbuf)); //Cleaning operation, but memset is generally used, which is more powerful
printf("wait form client request...\\
");
msgrcv (msgid, & amp;msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0); //Read messages from the message queue
printf ("Get %ldL msg\\
", msgbuf.msgtype); //Print message type
printf ("text[0] = %#x\\
", msgbuf.text[0]); //Print message content

//Determine the message type to determine which device it is
switch(msgbuf.msgtype){<!-- -->
case 1L:
//The type of 1L is the message type of LED. It is locked at this time and is unlocked after waiting for the message content, that is, the control command word to be copied, and wakes up the LED thread pthread_led.c through pthread_cond_signal to perform specific hardware operations on the LED.
pthread_mutex_lock( & amp;mutex_led);
printf("hello led\\
");
cmd_led = msgbuf.text[0];
pthread_mutex_unlock( & amp;mutex_led);
pthread_cond_signal( & amp;cond_led);
break;
case 2L:
//2L represents the message type of beep
//I believe everyone here is talented and understands the LED above, so beeping is not a problem.
pthread_mutex_unlock( & amp;mutex_buzzer);
printf("hello beep1\\
");
pthread_mutex_lock( & amp;mutex_buzzer);
cmd_buzzer = msgbuf.text[0];
pthread_mutex_unlock( & amp;mutex_buzzer);
pthread_cond_signal( & amp;cond_buzzer);
break;
case 3L:
pthread_mutex_lock( & amp;mutex_led);
printf("hello seg\\
");
cmd_seg = msgbuf.text[0];
pthread_mutex_unlock( & amp;mutex_led);
pthread_cond_signal( & amp;cond_led);
break;
case 4L:
pthread_mutex_lock( & amp;mutex_sqlite);
printf("hello fan\\
");
cmd_fan = msgbuf.text[0];
\t\t\t\t
int fan_fd = open_port("/dev/ttyUSB0"); //Open the device
if(fan_fd < 0){<!-- -->
printf("open failed\\
");
}
set_com_config(fan_fd, 115200, 8, 'N', 1); //Set serial port parameters
\t\t\t\t
char cmdbuf[4] = {<!-- -->0};
if(cmd_fan == 0x21){<!-- -->
strcpy(cmdbuf,"1\\
"); //Note, be sure to add \\
, because the serial port assistant adds \\
 by default, so we need to add it manually here
write(fan_fd,cmdbuf,sizeof(cmdbuf)/sizeof(cmdbuf[0]));
sleep(2);
}
if(cmd_fan == 0x20){<!-- -->
strcpy(cmdbuf,"0\\
");
write(fan_fd,cmdbuf,sizeof(cmdbuf)/sizeof(cmdbuf[0]));
sleep(2);
}
char buf[32] = {<!-- -->0};
//get data from zigbee
read(fan_fd, & amp;buf,sizeof(buf));
printf("sizeof(buf) = %d.\\
",sizeof(buf));
printf(">>>>>>%s\\
",buf);
sleep(1);
pthread_mutex_unlock( & amp;mutex_sqlite);
break;
default:
break;
}
}
}
#endif

Next, let’s take a look at serial port programming under Linux. Why should we learn this? In fact, we need to communicate with the zigbee module through USB. Then it is nothing more than setting the communication rate, check bit, stop bit and other parameters:
First take a look at the linuxuart.h file:

#ifndef __LINUX_UART_H_
#define __LINUX_UART_H_

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <termios.h>
#include <string.h>
#include "data_global.h"

extern int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits);
extern int open_port(char *com_port);
extern void USB_UART_Config(char* path, int baud_rate);
#endif

Let’s take a look at the linuxuatr.c file:

#include "linuxuart.h"

int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits)
{<!-- -->
struct termios new_cfg, old_cfg;
int speed;
/*Save the original serial port configuration*/
if (tcgetattr(fd, & amp;old_cfg) != 0){<!-- -->
perror("tcgetattr");
return -1;
}

new_cfg =old_cfg;

/*Configure to raw mode*/
cfmakeraw(&new_cfg);
new_cfg.c_cflag & amp;= ~CSIZE;

/*Set baud rate*/
switch(baud_rate)
{<!-- -->
case 2400:{<!-- -->
speed = B2400;
break;
}
case 4800:{<!-- -->
speed = B4800;
break;
}
case 9600:{<!-- -->
speed = B9600;
break;
}
case 19200:{<!-- -->
speed = B19200;
break;
}
case 38400:{<!-- -->
speed = B38400;
break;
}

default:
case 115000:{<!-- -->
speed = B115200;
break;
}
}

cfsetispeed(& amp;new_cfg, speed);
cfsetospeed(& amp;new_cfg, speed);

/*Set data bits*/
switch(data_bits)
{<!-- -->
case 7:{<!-- -->
new_cfg.c_cflag |= CS7;
break;
}
default:
case 8:{<!-- -->
new_cfg.c_cflag |= CS8;
break;
}
}

/*Set parity bit*/
switch (parity)
{<!-- -->
default:
case 'n':
case 'N':{<!-- -->
new_cfg.c_cflag & amp;= ~PARENB;
new_cfg.c_iflag & amp;= ~INPCK;
break;
}
case 'o':
case 'O':{<!-- -->
new_cfg.c_cflag |= (PARODD |PARENB);
new_cfg.c_iflag |= INPCK;
break;
}
case 'e':
case 'E':{<!-- -->
new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag & amp;= ~PARODD;
new_cfg.c_iflag |= INPCK;
break;
}
case 's':
case 'S':{<!-- -->
new_cfg.c_cflag & amp;= ~PARENB;
new_cfg.c_cflag & amp;= ~CSTOPB;
break;
}
}

/*Set stop bit*/
switch (stop_bits)
{<!-- -->
default:
case 1:{<!-- -->
new_cfg.c_cflag & amp;= ~CSTOPB;
break;
}
case 2:{<!-- -->
new_cfg.c_cflag |= CSTOPB;
break;
}
}

/*Set waiting time and minimum received characters*/
new_cfg.c_cc[VTIME] = 0;
new_cfg.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
if ((tcsetattr(fd, TCSANOW, & amp;new_cfg)) != 0)
{<!-- -->
perror("tcsetattr");
return -1;
}

return 0;
}


int open_port(char *com_port)
{<!-- -->
int fd;

/*Open serial port*/
fd = open(com_port, O_RDWR|O_NOCTTY|O_NDELAY);
if (fd < 0){<!-- -->
perror("open serial port");
return -1;
}

/*Restore serial port blocking state*/
if (fcntl(fd, F_SETFL, 0) < 0){<!-- -->
perror("fcntl F_SETFL\\
");
}

/*Determine whether it is a terminal device*/
if (isatty(fd) == 0){<!-- -->
perror("This is not a terminal device");
}

return fd;
}


/*------------------------CH340------------------------- --*/
void USB_UART_Config(char* path, int baud_rate)
{<!-- -->
int fd;
fd = open_port(path);
if(fd < 0){<!-- -->
printf("open %s failed\\
",path);
return ;
}
if (set_com_config(fd, baud_rate, 8, 'N', 1) < 0)
{<!-- -->
perror("set_com_config");
return ;
}
close(fd);
return ;
}

Are these functions familiar? In fact, they are the serial port assistants we often use! It’s software, there’s no graphical interface anymore!

3. Phenomenon display

When the fan is stationary, the following is true:
Please add a picture description
The picture below is a picture of the fan rotating:
Please add image description
The following figure shows the control command words displayed on the terminal:
Open display:
Please add an image description
Turn off display:
Please add image description
It can also be seen here that it is consistent with the code information; the message type is 4L, the control command words are 0x21 and 0x20; and the printed information is also correct;

Summary

The sharing of this issue ends here. It should be noted that everyone must adjust Zigbee first to ensure its normal operation, then learn Linux serial port programming, and then integrate these into the project to realize web control of Zigbee terminal node hardware. ;Finally, if you have gained anything, you can like and save it. Your recognition is my creation. motivation, let’s work hard together!