国产ARM/RISCV与OpenHarmony物联网项目(三)网关设备控制

发布于:2025-06-21 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、设备控制界面与功能设计

程序界面运行与设计效果如下:

设备控制相关程序调用关系图如下:

其中device_control.html程序为网页界面显示程序,led_alarm.cgi程序为光线数据的报警超限数据设置与管理,led_control.cgi程序功能为对Led灯的开关控制。gas_alarm.cgi程序为气体数据的报警超限数据设置与管理,gas_control.cgi程序功能为对蜂鸣器的开关控制。

二、device_control.html程序分析与设计

程序实现了一个设备控制页面,主要用于控制光线和气体相关设备,包括 LED 灯和蜂鸣器。用户可以切换设备的自动 / 手动模式、设置警报阈值、手动开关设备,同时页面会定时更新设备的连接状态和工作状态。具体功能如下:

页面结构与样式

  • 使用了 Bootstrap 框架来构建页面布局,提供了响应式的网格系统和样式。

  • 引入了 bootstrap-switch.min.cssbootstrap-switch.min.js 来实现开关按钮的样式和交互。

  • 引入了 echarts.min.js (虽然代码中未使用),可能用于后续的数据可视化。

页面加载事件

  • 当页面加载完成时,会调用 myFunction 函数,该函数会进一步调用 node_lednode_buzzer 函数,用于初始化设备状态。

光线设置部分

  • 提供一个开关按钮 led_auto_config 用于切换光线控制的自动模式和手动模式。

    • 自动模式开启时,启用光线警报阈值的输入框和提交按钮,禁用 LED 灯的手动点击事件。

    • 自动模式关闭时,禁用光线警报阈值的输入框和提交按钮,启用 LED 灯的手动点击事件。

  • 显示一个 LED 灯的图片,点击图片可以切换 LED 灯的状态(开 / 关)。

  • 提供一个输入框和提交按钮,用于设置光线警报的阈值。

气体设置部分

  • 提供一个开关按钮 gas_auto_config 用于切换气体控制的自动模式和手动模式。

    • 自动模式开启时,禁用气体警报阈值的输入框和提交按钮。

    • 自动模式关闭时,启用气体警报阈值的输入框和提交按钮。

  • 显示一个蜂鸣器的图片,点击图片可以切换蜂鸣器的状态(开 / 关)。

  • 提供一个输入框和提交按钮,用于设置气体警报的阈值。

设备状态更新

  • 使用 setInterval 函数每 3 秒调用一次 node_lednode_buzzer 函数,实时更新设备的连接状态和状态信息。

    • node_led 函数通过 AJAX 请求获取 LED 灯的状态信息,并根据返回结果更新 LED 灯的图片和连接状态图标。

    • node_buzzer 函数通过 AJAX 请求获取蜂鸣器的状态信息,并根据返回结果更新蜂鸣器的图片和连接状态图标。

阈值设置与状态切换

  • button_led_alarm 函数用于提交光线警报阈值的设置。

  • button_gas_alarm 函数用于提交气体警报阈值的设置。

  • changeStatus 函数用于切换设备的状态(开 / 关),并通过 AJAX 请求将状态信息发送到服务器。

1、程序功能分析与设计

1. HTML 头部(<head> 部分)

<head>
    <meta charset="utf-8">
    <title>设备控制</title>
    <link href="css/bootstrap.css" type="text/css" rel="stylesheet">
    <link href="css/bootstrap-switch.min.css" type="text/css" rel="stylesheet" />
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <script type="text/javascript" src="js/bootstrap-switch.min.js"></script>
    <script type="text/javascript" src="js/echarts.min.js"></script>
</head>
  • 字符编码设置:通过 <meta charset="utf-8"> 设置页面使用 UTF - 8 编码。

  • 页面标题<title>设备控制</title> 定义了页面的标题。

  • 样式引入:引入了 Bootstrap 框架的 CSS 文件和 bootstrap-switch 的 CSS 文件,用于页面布局和开关样式。

  • 脚本引入:引入了 jQuery、Bootstrap、bootstrap-switch 和 ECharts 的 JavaScript 文件,其中 ECharts 引入后未使用。

2. 页面加载事件处理

<script>
    function myFunction() {
        console.log('页面加载完成,函数被调用');
        node_led();
        node_buzzer();
    }
    window.addEventListener('load', myFunction);
</script>
  • 当页面加载完成时,myFunction 函数会被调用,该函数会调用 node_lednode_buzzer 函数来初始化 LED 灯和蜂鸣器的状态。

3. 页面主体(<body> 部分)

<div id="device_control">
    <!-- 光线设置部分 -->
    <div class="col-md-8" align="middle" style="margin:5% 20%;">
        <div class="panel panel-default">
            <div class="panel-heading">
                <label>光线设置</label>
                <img id="gd32_led_conn" src="img/disconnect_device.png" width="3.5%" style="float: right;">
            </div>
            <div class="panel-body">
                <!-- 自动模式开关 -->
                <div style="float: right; width: 65%;">
                    <p3>自动模式开关</p>
                    <input type="checkbox" id="led_auto_config" />
                </div>
                <!-- LED 灯图片 -->
                <div class="col-md-4" id="light-img" style="float: left;">
                    <img id="led" src="img/led_off.png" class="img-responsive center-block"
                        onmousedown="changeStatus(this,'cgi-bin/led_control.cgi')">
                    <label id="led_txt">LED灯手动开关</label>
                </div>
                <!-- 光线警报阈值输入 -->
                <div class="col-md-3" style="float: right; width: 65%; margin: 5% auto;">
                    <p3>光线警报的阈值</p>
                    <div class="input-group">
                        <input type="input" class="form-control" id="input_led_alarm" disabled="true"/>
                        <span class="input-group-btn"><button type="submit" class="btn btn-primary"
                                id="btn_led_alarm" onclick="button_led_alarm()" disabled="true">提交</button></span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- 气体设置部分 -->
    <div class="col-md-8" align="middle" style="margin:0% 20%;">
        <div class="panel panel-default">
            <div class="panel-heading">
                <label>气体设置</label>
                <img id="l431_buzzer_conn" src="img/disconnect_device.png" width="3.5%" style="float: right;">
            </div>
            <div class="panel-body">
                <!-- 自动模式开关 -->
                <div style="float: right; width: 65%;">
                    <p3>自动模式开关</p>
                    <input type="checkbox" id="gas_auto_config" />
                </div>
                <!-- 蜂鸣器图片 -->
                <div class="col-md-4" id="gas-img" style="float: left;">
                    <img id="buzzer" src="img/buzzer_off.png" class="img-responsive center-block"
                        onmousedown="changeStatus(this,'cgi-bin/node_buzzer.cgi')">
                    <label>蜂鸣器状态</label>
                </div>
                <!-- 气体警报阈值输入 -->
                <div class="col-md-3" style="float: right; width: 65%; margin: 5% auto;">
                    <p3>气体警报的阈值</p>
                    <div class="input-group">
                        <input type="input" class="form-control" id="input_gas_alarm" />
                        <span class="input-group-btn"><button type="button" class="btn btn-primary"
                                id="btn_gas_alarm" onclick="button_gas_alarm()">提交</button></span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
  • 光线设置部分:包含 LED 灯的自动模式开关、LED 灯图片(可手动开关)和光线警报阈值输入框及提交按钮。

  • 气体设置部分:包含蜂鸣器的自动模式开关、蜂鸣器图片(可手动开关)和气体警报阈值输入框及提交按钮。

4. 开关插件初始化

$("#led_auto_config").bootstrapSwitch({
    onText: "ON",
    offText: "OFF",
    onColor: "success",
    offColor: "danger",
    size: "normal",
    onSwitchChange: function (event, state) {
        const ledImg = document.getElementById('led');
        const ledLabel = document.getElementById('led_txt');
        if (state == true) {
            remove_attr("input_led_alarm", "disabled");
            remove_attr("btn_led_alarm", "disabled");
            ledImg.onmousedown = null;
            ledLabel.innerHTML = "LED状态"
        } else {
            set_attr("input_led_alarm", "disabled", "disabled");
            set_attr("btn_led_alarm", "disabled", "disabled");
            ledImg.onmousedown = function () {
                changeStatus(this, 'cgi-bin/led_control.cgi');
            };
            ledLabel.innerHTML = "LED手动开关"
        }
    }
});

$("#gas_auto_config").bootstrapSwitch({
    onText: "ON",
    offText: "OFF",
    onColor: "success",
    offColor: "danger",
    size: "normal",
    onSwitchChange: function (event, state) {
        if (state == true) {
            set_attr("input_gas_alarm", "disabled", "disabled");
            set_attr("btn_gas_alarm", "disabled", "disabled");
        } else {
            remove_attr("input_gas_alarm", "disabled");
            remove_attr("btn_gas_alarm", "disabled");
        }
    }
});
  • 使用 bootstrap-switch 插件初始化 LED 灯和蜂鸣器的自动模式开关。

  • 当开关状态改变时,会根据状态启用或禁用相应的输入框和按钮,同时处理 LED 灯的点击事件。

5. 辅助函数

function set_attr(iid, attr, val) {
    document.getElementById(iid).setAttribute(attr, val);
}

function remove_attr(iid, attr) {
    document.getElementById(iid).removeAttribute(attr);
}
  • set_attr 函数用于给指定 ID 的 HTML 元素设置属性。

  • remove_attr 函数用于移除指定 ID 的 HTML 元素的属性。

6. 获取初始警报阈值

  • 光照报警值通过获取url: "cgi-bin/led_alarm.cgi?get"

  • 气体报警值通过获取url: "cgi-bin/gas_alarm.cgi?get"

$.ajax({
    cache: false,
    async: true,
    dataType: 'Text',
    type: 'get',
    url: "cgi-bin/led_alarm.cgi?get",
    success: function (data) {
        console.log("led_alarm:", data);
        document.getElementById("input_led_alarm").placeholder = data;
    }
})

$.ajax({
    cache: false,
    async: true,
    dataType: 'Text',
    type: 'get',
    url: "cgi-bin/gas_alarm.cgi?get",
    success: function (data) {
        console.log("gas_alarm:", data);
        document.getElementById("input_gas_alarm").placeholder = data;
    }
})
  • 通过 AJAX 请求获取 LED 灯和气体的初始警报阈值,并将其设置为输入框的占位符。

7. 定时更新设备状态

setInterval(function () {
    node_led();
    node_buzzer();
}, 3000)
  • 每 3 秒调用一次 node_lednode_buzzer 函数,更新 LED 灯和蜂鸣器的连接状态和工作状态。

  • noode_led函数调用url: "cgi-bin/led_control.cgi?get"

  • node_buzzer函数调用url: "cgi-bin/gas_control.cgi?get"

8. 设备状态更新函数

function node_led() {
    $.ajax({
        cache: false,
        async: true,
        dataType: 'text',
        type: 'get',
        url: "cgi-bin/led_control.cgi?get",
        success: function (data) {
            const dataArray = data.split(',');
            if (dataArray.length >= 2) {
                const firstField = parseInt(dataArray[0], 10);
                const ledStatus = parseInt(dataArray[1], 10);
                if (!isNaN(firstField) && firstField!== 0) {
                    is_conn("gd32_led_conn", true);
                } else {
                    is_conn("gd32_led_conn", false);
                }
                if (ledStatus === 1) {
                    document.getElementById("led").src = "img/led_on.png";
                } else if (ledStatus === 0) {
                    document.getElementById("led").src = "img/led_off.png";
                }
            } else {
                console.error('接收到的数据格式不正确,缺少必要字段');
                is_conn("gd32_led_conn", false);
            }
        },
        error: function () {
            is_conn("gd32_led_conn", false);
        }
    });
}

function node_buzzer() {
    $.ajax({
        cache: false,
        async: true,
        dataType: 'Text',
        type: 'get',
        url: "cgi-bin/gas_control.cgi?get",
        success: function (data) {
            if (data != "") {
                is_conn("l431_buzzer_conn", true);
            } else {
                is_conn("l431_buzzer_conn", false);
            }
            if (data == 1) {
                document.getElementById("buzzer").src = "img/buzzer_on.png";
            } else if (data == 0) {
                document.getElementById("buzzer").src = "img/buzzer_off.png";
            }
        },
        error: function () {
            is_conn("l431_buzzer_conn", false);
        }
    })
}
  • node_led 函数通过 AJAX 请求获取 LED 灯的状态信息,根据返回结果更新 LED 灯的连接状态图标和图片。

  • node_buzzer 函数通过 AJAX 请求获取蜂鸣器的状态信息,根据返回结果更新蜂鸣器的连接状态图标和图片。

9. 警报阈值提交函数

function button_led_alarm() {
    var alarm_data = document.getElementById("input_led_alarm").value;
    sender_bool("cgi-bin/led_alarm.cgi", alarm_data);
}

function button_gas_alarm() {
    var alarm_data = document.getElementById("input_gas_alarm").value;
    sender_bool("cgi-bin/gas_alarm.cgi", alarm_data);
}
  • button_led_alarm 函数获取用户输入的光线警报阈值,并调用 sender_bool 函数将其发送到服务器。

  • button_gas_alarm 函数获取用户输入的气体警报阈值,并调用 sender_bool 函数将其发送到服务器。

10. 设备状态切换函数

function changeStatus(obj, cgi) {
    on_use = 1;
    var img = obj.src;
    if (img.indexOf("on") != -1) {
        obj.src = "img/" + obj.id + "_off.png";
        sender_bool(cgi, "off");
    } else {
        obj.src = "img/" + obj.id + "_on.png";
        sender_bool(cgi, "on");
    }
}
  • 当用户点击 LED 灯或蜂鸣器图片时,调用 changeStatus 函数,根据图片的当前状态切换图片,并调用 sender_bool 函数将状态信息发送到服务器。

11. 连接状态更新函数

function is_conn(iid, bool) {
    org = document.getElementById(iid);
    if (bool) {
        org.src = "img/connect_device.png";
    } else {
        org.src = "img/disconnect_device.png";
    }
}
  • is_conn 函数根据传入的布尔值更新设备连接状态图标的图片。

12. 数据发送函数

function sender_bool(cgi, bool) {
    $.ajax({
        cache: false,
        async: true,
        dataType: 'Text',
        type: 'get',
        url: cgi + "?set" + "&" + bool,
        success: function (data) {
            console.log("set ok");
        }
    })
}
  • sender_bool 函数通过 AJAX 请求将设备状态或警报阈值信息发送到服务器。

三、led_alarm程序分析与设计

程序创建了一个基于 HTTP 的接口,用于与硬件设备(如 E53_IA1 环境监测模块)进行交互。程序通过共享内存与其他进程通信,主要功能包括:

  1. 定义了共享内存数据结构st_sys,包含温度、湿度、光照等环境参数

  2. 通过共享内存获取和设置环境监测数据

  3. 处理 HTTP GET 和 SET 请求:

    • GET 请求返回当前光照强度最大值

    • SET 请求允许设置光照强度的阈值

1、程序流程分析与设计

程序的运行流程可以概括为以下几个主要步骤:

初始化阶段

  • 程序开始执行,初始化变量并设置信号处理函数。

  • 创建或连接到键值为 3456 的共享内存段。

共享内存操作

  • 检查共享内存设置是否成功,若失败则输出错误信息并退出。

  • 从共享内存读取数据到本地副本。

HTTP 响应准备

  • 设置 HTTP 响应头为 "Content-type:text/html"。

  • 获取环境变量 QUERY_STRING,该变量包含客户端发送的请求参数。

共享内存参数设置

  • 设置共享内存中的控制参数:

    • msg_type = CMD_SET(命令类型为设置)

    • node_id = E53_IA1(节点类型为 E53_IA1)

    • data_flag 自增(标记更新次数)

请求处理

  • 检查 QUERY_STRING 中是否包含 "get":

    • 若包含,则输出共享内存中的 ill_max 值(光照强度阈值)。

  • 检查 QUERY_STRING 中是否包含 "set":

    • 若包含,则解析参数中的新阈值,更新共享内存中的 ill_max 值,并输出确认信息和当前光照状态。

资源释放

  • 分离共享内存段,释放相关资源。

  • 程序结束。

2、程序功能分析与设计

数据结构定义

struct st_sys {
    unsigned char temp_val;  // 温度值
    unsigned char humi_val;  // 湿度值
    unsigned char light_sw;  // 灯光开关状态
    unsigned char buzz_sw;   // 蜂鸣器开关状态
    unsigned int ill_val;    // 光照强度值
    unsigned int gas_val;    // 气体浓度值
    unsigned int ill_max;    // 光照强度最大值
    unsigned int gas_max;    // 气体浓度最大值
    unsigned char msg_type;  // 请求类型
    unsigned char node_id;   // 节点ID
    unsigned char data_flag;//数据更新标记 
    unsigned char control_flag;//控制更新标记
    unsigned char set_flag;//设置更新标记      
};

这个结构体定义了系统的各种状态参数和控制标志,是进程间通信的核心数据结构。

共享内存管理

// 设置共享内存
void* set_web_shm(void) {
    int shmid;
    void* shmaddr = (void*)0;

    // 创建或获取共享内存段
    if ((shmid = shmget((key_t)3456, sizeof(struct st_sys), 0666 | IPC_CREAT)) < 0) {
        perror("shmget error");
        return NULL;
    }
    // 将共享内存段附加到当前进程的地址空间
    if ((shmaddr = shmat(shmid, (void*)0, 0)) == (char*)-1) {
        perror("shmat error");
        return NULL;
    }
    return shmaddr;
}

这个函数负责创建或连接到共享内存段,返回共享内存的地址指针。

信号处理

// 信号处理函数,用于分离共享内存并退出程序
void signal_handler(int signum) {
    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }
    exit(0);
}

这个信号处理函数确保程序在接收到终止信号时能正确分离共享内存,避免资源泄漏。

主程序逻辑

int main() {
    // ... 省略部分代码 ...

    // 设置共享内存
    if ((shm_dev = (struct st_sys*)set_web_shm()) == NULL) {
        fprintf(stderr, "Failed to set up shared memory.\n");
        return 1;
    }
    
    // 从共享内存中读取数据到本地副本
    memcpy(g_dev, shm_dev, sizeof(struct st_sys));
    
    // 设置 HTTP 响应头
    printf("Content-type:text/html\n\n");

    // 获取环境变量中的查询字符串
    query_string = getenv("QUERY_STRING");

    // 设置命令类型和节点ID,并更新标记
    shm_dev->msg_type = CMD_SET;
    shm_dev->node_id = E53_IA1;
    shm_dev->data_flag++;//更新次数加1    
    shm_dev->set_flag++;//更新次数加1

    // 处理GET请求
    if (strstr(query_string, "get")) {
        printf("%d", shm_dev->ill_max);
    } 

    // 处理SET请求
    if (strstr(query_string, "set")) {
        // 从查询字符串中解析报警阈值
        sscanf(query_string, "%*[^&]&%d", &alarm);
        shm_dev->ill_max = alarm;
        printf("%d", alarm);

        printf("ok\r\n");
        // 根据当前光照值输出状态
        if (shm_dev->ill_val > 0) {
            printf("1");
        } else {
            printf("0");
        }
    }

    // 分离共享内存
    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }

    return 0;
}

主程序通过环境变量获取 HTTP 查询字符串,根据查询参数处理 GET 或 SET 请求,并通过共享内存与其他进程通信。

四、gas_alarm程序分析与设计

1、程序流程分析与设计

gas_alarm程序流程与led_alarm基本一致。

2、程序功能分析与设计

gas_alarm程序与led_alarm程序功能基本一致,只是从共享内存中获取的数据不同。

int main() {

    char *query_string = "";
    unsigned int alarm = 0;

    // 设置共享内存
    if ((shm_dev = (struct st_sys*)set_web_shm()) == NULL) {
        fprintf(stderr, "Failed to set up shared memory.\n");
        return 1;
    }
    // 从共享内存中读取数据
    memcpy(g_dev, shm_dev, sizeof(struct st_sys));
    // 设置 HTTP 响应头
    printf("Content-type:text/html\n\n");

    query_string = getenv("QUERY_STRING");

    shm_dev->msg_type = CMD_SET;//命令类型
    shm_dev->node_id = E53_SF1;//节点类型
    shm_dev->data_flag++;//更新次数加1    
    shm_dev->set_flag++;//更新次数加1


    if (strstr(query_string, "get")) {
        printf("%d", shm_dev->gas_max);
    } 

    if (strstr(query_string, "set")){
        sscanf(query_string, "%*[^&]&%d", &alarm);
        shm_dev->gas_max = alarm;
        printf("%d", alarm);

        printf("ok\r\n");
        if (shm_dev->gas_val > 0) {
            printf("1");
        }else{
            printf("0");
        }
    }

    //分离共享内存
    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }

    return 0;
}

五、led_control程序分析与设计

程序通过共享内存与其他进程进行数据交互,根据 Web 客户端的请求实现了 LED 控制和光照强度、灯光开关状态的数据获取功能,同时对共享内存进行了有效的管理,确保程序在运行过程中能够正确地处理信号和释放资源。

1、程序流程分析与设计

2、程序功能分析与设计

led_control.c 是一个 CGI(Common Gateway Interface)程序,其核心功能是借助共享内存实现 LED 控制以及数据获取,以响应来自 Web 客户端的请求。以下是对代码各部分功能设计:

头文件与宏定义

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>

#define CMD_DATA 0x01
#define CMD_CTL 0x02
#define CMD_SET 0x03

#define E53_IA1 0x01
#define E53_SF1 0x02
  • 头文件:引入了一系列标准库和系统库的头文件,用于支持文件操作、进程通信、信号处理等功能。

  • 宏定义:定义了命令类型(如 CMD_DATACMD_CTLCMD_SET)和节点类型(如 E53_IA1E53_SF1)的常量。

共享内存数据结构

struct st_sys {
    unsigned char temp_val;  // 温度值
    unsigned char humi_val;  // 湿度值
    unsigned char light_sw;  // 灯光开关状态
    unsigned char buzz_sw;   // 蜂鸣器开关状态
    unsigned int ill_val;    // 光照强度值
    unsigned int gas_val;    // 气体浓度值
    unsigned int ill_max;    // 光照强度最大值
    unsigned int gas_max;    // 气体浓度最大值
    unsigned char msg_type; //请求类型
    unsigned char node_id; //节点ID
    unsigned char data_flag;//数据更新标记 
    unsigned char control_flag;//控制更新标记
    unsigned char set_flag;//设置更新标记     
};

struct st_sys* shm_dev;
struct st_sys g_dev[1];
  • 结构体 st_sys:用于存储系统的各种状态信息,包括温度、湿度、灯光和蜂鸣器的开关状态、光照强度、气体浓度等,同时包含请求类型、节点 ID 和更新标记。

  • 指针 shm_dev:用于指向共享内存区域。

  • 数组 g_dev:用于临时存储从共享内存中读取的数据。

共享内存操作函数

void* set_web_shm(void) {
    int shmid;
    void* shmaddr = (void*)0;

    if ((shmid = shmget((key_t)3456, sizeof(struct st_sys), 0666 | IPC_CREAT)) < 0) {
        perror("shmget error");
        return NULL;
    }
    if ((shmaddr = shmat(shmid, (void*)0, 0)) == (char*)-1) {
        perror("shmat error");
        return NULL;
    }
    return shmaddr;
}

void signal_handler(int signum) {
    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }
    exit(0);
}
  • set_web_shm 函数:负责创建或获取一个共享内存段,并将其附加到当前进程的地址空间。若操作失败,会输出错误信息并返回 NULL

  • signal_handler 函数:作为信号处理函数,在接收到特定信号时,将共享内存从当前进程的地址空间中分离,并退出程序。

主函数 main

int main() {
    char *query_string = "";

    if ((shm_dev = (struct st_sys*)set_web_shm()) == NULL) {
        fprintf(stderr, "Failed to set up shared memory.\n");
        return 1;
    }
    memcpy(g_dev, shm_dev, sizeof(struct st_sys));

    printf("Content-type:text/html\n\n");

    query_string = getenv("QUERY_STRING");

    shm_dev->node_id = E53_IA1;
    shm_dev->data_flag++;//更新次数加1
    shm_dev->control_flag++;//更新次数加1

    if (strstr(query_string, "get")) {
        shm_dev->msg_type = CMD_DATA;
        printf("%d,%d", shm_dev->ill_val, shm_dev->light_sw);
    } 

    if (strstr(query_string, "set")) {
        shm_dev->msg_type = CMD_CTL;

        if (strstr(query_string, "on") != NULL) {
            printf("on");
            shm_dev->light_sw = 1;
        } else if (strstr(query_string, "off") != NULL) {
            printf("off");
            shm_dev->light_sw = 0;
        }
        printf("ok\r\n");
        if (shm_dev->ill_val > 0) {
            printf("1");
        } else {
            printf("0");
        }
    }

    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }

    return 0;
}
  • 共享内存初始化:调用 set_web_shm 函数设置共享内存,若失败则输出错误信息并退出程序。然后将共享内存中的数据复制到本地数组 g_dev 中。

  • HTTP 响应头设置:输出 HTTP 响应头,表明返回的内容类型为 HTML。

  • 获取查询字符串:从环境变量中获取 QUERY_STRING,该字符串包含了客户端的请求信息。

  • 设置节点类型和更新标记:将节点类型设置为 E53_IA1,并将更新标记加 1。

  • 处理请求

    • 若查询字符串中包含 get,则将命令类型设置为 CMD_DATA,并输出光照强度和灯光开关状态。

    • 若查询字符串中包含 set,则将命令类型设置为 CMD_CTL,根据查询字符串中的 onoff 关键字来控制灯光的开关状态,并输出相应的响应信息,最后根据光照强度是否大于 0 输出 10

  • 分离共享内存:在处理完请求后,将共享内存从当前进程的地址空间中分离。

六、gas_control程序分析与设计

1、程序流程分析与设计

gas_control程序流程与led_control基本一致。

2、程序功能分析与设计

gas_control程序与gas_control程序功能基本一致,只是从共享内存中获取与设置的数据不同。

int main() {
    char *query_string = "";

    // 设置共享内存
    if ((shm_dev = (struct st_sys*)set_web_shm()) == NULL) {
        fprintf(stderr, "Failed to set up shared memory.\n");
        return 1;
    }
    // 从共享内存中读取数据
    memcpy(g_dev, shm_dev, sizeof(struct st_sys));

    // 设置 HTTP 响应头
    printf("Content-type:text/html\n\n");

    query_string = getenv("QUERY_STRING");


    shm_dev->node_id = E53_SF1;//节点类型
    shm_dev->data_flag++;//更新次数加1
    shm_dev->control_flag++;//更新次数加1

    if (strstr(query_string, "get")) {
        shm_dev->msg_type = CMD_DATA;//命令类型
        printf("%d,%d", shm_dev->gas_val,shm_dev->buzz_sw);

    } 

    if (strstr(query_string, "set")){
        shm_dev->msg_type = CMD_CTL;//命令类型

        if (strstr(query_string, "on") != NULL) {
            printf("on");
            shm_dev->buzz_sw = 1;
        } else if (strstr(query_string, "off") != NULL) {
            printf("off");
            shm_dev->buzz_sw = 0;
        }
        printf("ok\r\n");
        if (shm_dev->gas_val > 0) {
            printf("1");
        }else{
            printf("0");
        }
    }

    //分离共享内存
    if (shmdt(shm_dev) == -1) {
        perror("shmdt error");
    }

    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到