首页 > 其他分享 >网页控制从机操作

网页控制从机操作

时间:2023-06-26 20:55:13浏览次数:41  
标签:info 网页 val modbus 从机 obj key 操作 buf

2023.6.26 学习了整体的流程和框架的功能,理解了如何通过网页来控制从机

说明

涉及技术点:CGI,modbus,线程,共享内存,消息队列
实现平台:linux
缺陷:服务器没有自己写,CGi和modbus都是框架下面添加功能,没有纯手撸。
效果展示:linux打开服务器,win打开从机。实现效果是点击获取温度,能获取到从机设备保持寄存器,网页点击蜂鸣器开关,从机实现线圈改变。
image.png

image.png

  • 网页浏览器:用户的操作界面,输入和得到相关直接消息
  • 服务器:响应浏览器的请求,回复数据给浏览器,收发消息给CGI
  • CGI:收发消息给服务器,通讯输入输出服务程序
  • 服务程序:读取控制modbus设备,输入输出数据给CGI
  • modbus设备:接受与发送数据给服务程序

上代码

1.服务程序

struct msgbuf
{
    long mtype;
    char mtext[128];
}msg;


char buf[32]="";
modbus_t* ctx; //同一个句柄


//线程函数
void *handler(void *arg)
{
    uint16_t dest[32]={0};
    key_t key;
    //1.创建一个唯一的key值
    key = ftok("/a.c", 'A');
    if (key < 0)
    {
        perror("ftok err");
        return 0;
    }
    printf("key=%#x\n", key);
    //2.创建共享内存或打开,返回一个共享内存的id
    int shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
    if (shmid < 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(key, 128, 0777);
        }
        else
        {
            perror("shmget err");
            return 0;
        }
    }
    char *p = (char *)shmat(shmid, NULL, 0);
    printf("shmid=%d\n", shmid);
    //3.建立共享内存和虚拟地址得映射关系
    if (p == (char *)-1)
    {
        perror("shmat err");
        return 0;
    }
    // 将数据存入共享内存
    while(1)
    {
        sleep(1);
        modbus_read_registers(ctx, 0, 2, dest);
        
        sprintf(buf, "%d %d %d %d\n",dest[0],dest[1],dest[2],dest[3]);
	    //printf("%d %d %d %d",dest[0],dest[1],dest[2],dest[3]);
        strcpy(p,buf); //通过共享内存p来通信CGI
    }
}



int main(int argc, char const *argv[])
{
    ctx = modbus_new_tcp("192.168.50.151",502);
    modbus_set_slave(ctx,1);
    modbus_connect(ctx);

    pthread_t tid;
    if(pthread_create(&tid,NULL,handler,NULL) != 0)
    {
        printf("create thread err\n");
        modbus_free(ctx);
        return -1;
    }

    key_t key = ftok("/a.c", 'B');
    if (key < 0)
    {
        perror("ftok err.");
        return -1;
    }

    int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0777);
    if (msgid < 0)
    {
        if (errno == EEXIST)
        {
            msgid = msgget(key, 0777);
        }
        else
        {
            perror("msgget err.");
            return -1;
        }
    }
        
    while (1)
    {
        msgrcv(msgid,&msg,sizeof(msg),'B',0);//等待CGI传来消息,在执行操作
        if(strncmp(msg.mtext,"0 1",3) == 0)
        {
            modbus_write_bit(ctx, 0, 1);
        }
        else if(strncmp(msg.mtext,"0 0",3) == 0)
        {
            modbus_write_bit(ctx, 0, 0);
        }
        else if(strncmp(msg.mtext,"1 1",3) == 0)
        {
            modbus_write_bit(ctx, 1, 1);
        }
        else if(strncmp(msg.mtext,"1 0",3) == 0)
        {
            modbus_write_bit(ctx, 1, 0);
        }
    }
    modbus_close(ctx);
    modbus_free(ctx);

    pthread_join(tid, NULL);
    return 0;
}

2.CGI程序核心代码

struct msgbuf
{
    long mtype;
    char mtext[128];
};

int parse_and_process(char *input) //这个input是服务器输入的
{
    char val_buf[2048] = {0};
    strcpy(val_buf, input);
    // 这里可以根据接收的数据请求进行处理
    // 判断input的值
    if (strncmp(val_buf, "get", 3) == 0) //判断是不是get命令
    {
        // 创建唯一的key值
        key_t key = ftok("/a.c", 'A');
        if (key < 0)
        {
            perror("ftok err");
            return -1;
        }

        // 创建共享内存
        int shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
        if (shmid < 0)
        {
            if (errno == EEXIST)
            {
                shmid = shmget(key, 128, 0777);
            }
            else
            {
                perror("shmget err");
                return -1;
            }
        }
        // 建立共享内存和虚拟地址的映射关系
        char *p = (char *)shmat(shmid, NULL, 0);
        if (p == (char *)-1)
        {
            perror("shmat err");
            return -1;
        }

        // 将数据写入stdout
        strcpy(val_buf, p);  //将服务程序拿到的数值给val_buf,这样传给服务器
        log_console("%s\n", val_buf); // 打印语句判断是否写入成功
    }
    else
    {
        // 消息队列
        key_t key = ftok("/a.c", 'B');
        if (key < 0)
        {
            perror("ftok err");
            return -1;
        }
        // 创建消息队列
        int msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0777);
        if (msgid < 0)
        {
            if (errno == EEXIST)
            {
                msgid = msgget(key, 0777);
            }
            else
            {
                perror("msgget err");
                return -1;
            }
        }
        // 添加消息
        if (strncmp(val_buf, "1 1", 3) == 0)
        {
            struct msgbuf msg1 = {'B', "1 1"};
            msgsnd(msgid, &msg1, sizeof(msg1), 0);
            strcpy(val_buf, "打开灯");

        }
        else if (strncmp(val_buf, "1 0", 3) == 0)
        {
            struct msgbuf msg2 = {'B', "1 0"};
            msgsnd(msgid, &msg2, sizeof(msg2), 0);
            strcpy(val_buf, "关闭灯");
        }
        else if (strncmp(val_buf, "0 1", 3) == 0)
        {
            struct msgbuf msg3 = {'B', "0 1"};
            msgsnd(msgid, &msg3, sizeof(msg3), 0);
            strcpy(val_buf, "打开蜂鸣器");
        }
        else if (strncmp(val_buf, "0 0", 3) == 0)
        {
            struct msgbuf msg4 = {'B', "0 0"};
            msgsnd(msgid, &msg4, sizeof(msg4), 0);
            strcpy(val_buf, "关闭蜂鸣器");
        }
    }

    

    // 数据处理完成后,需要给服务器回复,回复内容按照http协议格式
    char reply_buf[HTML_SIZE] = {0};
    sprintf(reply_buf, "%sContent-Length: %ld\r\n\r\n", HTML_HEAD, strlen(val_buf));
    strcat(reply_buf, val_buf);
    log_console("post json_str = %s", reply_buf);

    // 向标准输出写内容(标准输出服务器已做重定向)
    fputs(reply_buf, stdout);  //输出到服务器

    return 0;
}

3.网页代码核心代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>数据采集系统</title>
</head>

<!--指定文件路径-->
<script src="js/xhr.js"></script>
<script>
	function fun(obj){
		//console.log(obj);
		//调用post接口  obj浏览器发送得数据  info服务器回复得数据
		XHR.post('/cgi-bin/web.cgi',obj,function(x,info){
			console.log("info:",info);
		});
		
	}
	function fun1(obj){
		//console.log(obj);
		//调用post接口  obj浏览器发送得数据  info服务器回复得数据
		XHR.post
		('/cgi-bin/web.cgi',obj,function(x,info)
			{
				console.log("info:",info);
			var v1 = document.getElementById("tem");
			console.log(v1);
			var arr = info.split(" "); 
			var buf = arr[0].split(":");
			v1.value = buf[0];
			}
		);
		
	}
	function fun2(obj){
		//console.log(obj);
		//调用post接口  obj浏览器发送得数据  info服务器回复得数据
		XHR.post('/cgi-bin/web.cgi',obj,function(x,info){
			console.log("info:",info);
		var v2 = document.getElementById("hum");
		console.log(v2);
		var arr = info.split(" ");
		var buf = arr[1].split(":");
		v2.value = buf[1];
		});
		
	}
</script>






<body>
	<div  style="color: bisque;background-color: burlywood;">
	<!-- input标签类型为文本输入框,name:控件名称、value:默认值、id:标识 -->
	温度
	<input type="text" name="template" value="" id="tem">
	<input type="button" name="tem"   value="获取温度"  checked="checked" id="get" onclick="fun1(id)">
	<br>
	湿度
	<input type="text" name="humhum" value="" id="hum">
	<input type="button" name="hum" value="获取湿度" checked="checked" id="get" onclick="fun2(id)">


	<!-- input标签类型为单选按钮,name:控件名称、checked表示默认选中 -->
	<!-- label标签将文本和按钮进行绑定,当点击文本时自动聚焦到按钮上
	for属性值要和input标签中的id值一致 -->
	<br>
	<label for="LED 1">LED灯  开:</label>
	<input type="radio" name="LED" value="1" checked="checked" id="LED 1" onclick="fun(id)">
	<label for="LED 0">   关:</label>
	<input type="radio" name="LED" value="0" checked="checked" id="LED 0" onclick="fun(id)">
	<br>
	<label for="BEEP 1"> 蜂鸣器  开:   </label>
	<input type="radio" name="BEEP" value="1" id="BEEP 1" onclick="fun(id)">
	<label for="BEEP 0">   关:</label>
	<input type="radio" name="BEEP" value="0" id="BEEP 0" onclick="fun(id)">
</div>
</body>


</html>



总结

image.png
用户看到的内容是一个网页,得到效果是点击获取温度,就会得到从机检测的温度,选择LED灯,从机就会打开或者关闭。
那么当用户按下获取温度按键后,执行了这些操作:

<input type="button" name="tem"   value="获取温度"  checked="checked" id="get" 
    onclick="fun1(id)">

在html文件中,这条代码被执行,然后进入到fun1(id)中。

function fun1(obj){
		//console.log(obj);
		//调用post接口  obj浏览器发送得数据  info服务器回复得数据
		XHR.post
		('/cgi-bin/web.cgi',obj,function(x,info)
			{
				console.log("info:",info);
			var v1 = document.getElementById("tem");
			console.log(v1);
			var arr = info.split(" "); 
			var buf = arr[0].split(":");
			v1.value = buf[0];
			}
		);

在这里面,调用了XHR函数,可以看到第一个为URL,传递参数为dataobjid(也就是get),然后回调函数,其中info为服务器回复数据

XHR = function()
{
    this.post = function(url, data, callback)
    {}	
}

于是当给了post接口,给了参数get,就是服务器写入了get参数

//其中stdin已经重定向了,为服务器写入
ret = fread(request_content + len, 1, content_length - len, stdin);
ret = parse_and_process(request_content);//写入的值作为参数传入到这个函数内

上面就可以得到request_content的现在已经写入了get这个参数

int parse_and_process(char *input)
{
    char val_buf[2048] = {0};
    strcpy(val_buf, input);
    // 这里可以根据接收的数据请求进行处理
    // 判断input的值
    if (strncmp(val_buf, "get", 3) == 0)
    {
        
    }
}

然后传入的值get就能作为判断执行操作

// 向标准输出写内容(标准输出服务器已做重定向)
    fputs(reply_buf, stdout);

操作完毕就向服务器输出拿到的结果。

XHR.post
		('/cgi-bin/web.cgi',obj,function(x,info)
			{
				console.log("info:",info);
			var v1 = document.getElementById("tem");
			console.log(v1);
			var arr = info.split(" "); 
			var buf = arr[0].split(":");
			v1.value = buf[0];
			}
		);

info为服务器回复的内容,现在就已经收到了具体的内容,然后用变量进行接收,接受前也进行了一下数据的处理

温度
	<input type="text" name="template" value="" id="tem">
	<input type="button" name="tem"   value="获取温度"  checked="checked" id="get" onclick="fun1(id)">
	<br>

对应上面的 document.getElementById("tem");找到了value就赋值了,id为tem,所以这个时候上代码中的value=“” 变为了value=“buf[0]” 然后我们才在网页上看到了显示的值。
这其中经历了,网页给服务器传值,服务器给CGI传值,CGI拿用户程序的值,用户查询一直在拿modbus设备的值。

标签:info,网页,val,modbus,从机,obj,key,操作,buf
From: https://www.cnblogs.com/moveddown/p/17506022.html

相关文章

  • ​​统信UOS服务器操作系统迁移docker目录​​
    原文链接:统信UOS服务器操作系统迁移docker目录hello,大家好啊,今天给大家带来一篇在统信UOS服务器操作系统上迁移docker目录的文章,在工作中我们会发现,当我们没有将/var目录单独分区的时候,运行docker容器后,会将根目录挤压,因此我们可以通过迁移docker目录的方式,释放根路径的磁盘空间,文......
  • 艺术 网页设计的12种颜色
    前不久,ColourLovers.com公布了一项调查结果。他们发现,美国前100大网站的Logo,主要使用12种颜色。其中,采用蓝色的网站最多,红色排在第二种,黄色排在第三种。 我把这12种颜色的RGB代码列出来,供将来自己做网页时参考。1.浅绿#8cc540  2.深绿#009f5d 3.暗蓝#019fa04.蓝色#019......
  • vue3.0之cookies的操作
    安装npminstallvue-cookiesimportVueCookiesfrom'vue-cookies'constcookies=VueCookiescookies.set('key值','字符串或变量','7d')//7d代表时间,存放7天cookies.get('key值')//取出key值对应的数据cookies.remove('ke......
  • Hyper-V是微软开发的一种虚拟化技术,它允许在一台物理计算机上创建和管理多个虚拟机。
    Hyper-V是微软开发的一种虚拟化技术,它允许在一台物理计算机上创建和管理多个虚拟机。虚拟机可以运行不同的操作系统,如Windows、Linux等。以下是关于Hyper-V的一些要点:虚拟化技术:Hyper-V是一种类型-1(裸金属)虚拟化技术,它直接运行在硬件上,而不需要一个宿主操作系统。这使得虚拟机能......
  • c# 操作mysql数据库的时候会出现 插入中文汉字变成问号?或者更新数据库时条件里有汉字,
    在mysql里面执行时没有问题的。c#操作会出现问号或者更新失败。原因是: 链接字符串的时候要设置Charset=utf8;不然就会按默认的服务器设置编码,通常会出问题。1、创建的数据库是按utf8编码格式。 2、表也是utf8格式。3、链接字符串增加Charset=utf8;如:"server=10.167.32......
  • mockito5.4.0单元测试(12) --spy一个真实的对象,使该真实对象可以被mock操作和verify验
    mockito官方文档地址:https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#spy//new一个真实对象Listlist=newLinkedList();Listspy=spy(list);//把这个真实对象放到spy方法里//optionally,youcanstuboutsomemethods:whe......
  • Visual Basic(简称VB)是一种编程语言,由微软公司开发。它是基于事件驱动的编程语言,主要用
    VisualBasic(简称VB)是一种编程语言,由微软公司开发。它是基于事件驱动的编程语言,主要用于Windows操作系统上的应用程序开发。在VisualBasic中,可以使用图形用户界面(GUI)来创建各种应用程序,包括桌面应用程序、数据库应用程序、Web应用程序等。VisualBasic提供了许多现成的控件和工......
  • 【HMS Core】web端网页应用集成账号服务,请求/oauth2/v3/token返回状态码403
    【问题描述】web端网页应用接入华为账号,请求/oauth2/v3/token返回状态码403请求代码:响应日志:【问题分析】这是由于跨域访问报错了,建议从服务器端调用token接口重试,不要把client_secret暴露到web端【解决方案】服务器端调用token接口参考链接:https://developer.huawei.com/consumer......
  • Selenium基础:特殊Dom结构操作 07
    特殊Dom结构是指对元素不能直接操作,需要进行特殊定位切换到它所在的Dom结构,然后才能对其元素进行操作1、windows弹窗--alertconfirmprompt使用driver.switch_to.alert方法alert类操作方法:accept():确定dismiss():取消text():获取弹出框内的内容send_keys(keysToSend):输入......
  • Git log日志操作-6
    Gitlog日志操作区别:Gitlog:作用域是本地版本库。查看的是commit-m提交的内容。只add未commit不会生成log信息。支持简单查看,顺序查看,按时间和作者筛选Gitblame:作用域是工作区。查看的是工作区的最新内容,即使修改,未add,commit也可以打印。功能类似于linux中的cat命令一.Gitlog1......