• GoAhead4.1.0 开发总结二(自定义使用)


    环境

    官方文档:https://www.embedthis.com/goahead/doc/

    源码下载: goahead-4.1.0-src.tgz

    系统平台:Ubuntu 12.04.4

    gcc version 4.6.3

    GoAhead自定义程序实现

    goahead 源码提供了 test 示例代码,参照 test 代码框架实现 goahead 常用的 GoActions过程和embedded JavaScript 等

    1.自定义代码编译与组成

    本文实现的代码运行与 arm 平台,为了便于后面源码的编译,单独配置一个makefile配置文件 .mk 文件用于自定义程序的编译

    复制 projects/goahead-linux-default.mk  重命名为  goahead-linux-arm-default.mk,并在此基础上做修改

    后面每次编译采用指定文件的方式编译

    make -f projects/goahead-linux-arm-default.mk

    在 goahead-4.1.0 下新建 m283-webs 文件夹,里面存放自定义 web 代码,包含文件如下所示

    goahead-linux-arm-default.mk 文件修改如下:

    修改1:平台与配置

    主要修改 ARCH(平台)   CC(编译环境) 以及编译的常用配置,可以用于裁剪代码大小,本例先放弃SSL,因为这个比较占ROM

    #
    #   goahead-linux-default.mk -- Makefile to build Embedthis GoAhead for linux
    #
    
    NAME                  := goahead
    VERSION               := 4.1.0
    PROFILE               ?= default
    #ARCH                  ?= $(shell uname -m | sed 's/i.86/x86/;s/x86_64/x64/;s/arm.*/arm/;s/mips.*/mips/')
    ARCH                  := arm
    CC_ARCH               ?= $(shell echo $(ARCH) | sed 's/x86/i686/;s/x64/x86_64/')
    OS                    ?= linux
    #CC                    ?= gcc
    CC                    := arm-fsl-linux-gnueabi-gcc
    CONFIG                ?= $(OS)-$(ARCH)-$(PROFILE)
    BUILD                 ?= build/$(CONFIG)
    LBIN                  ?= $(BUILD)/bin
    PATH                  := $(LBIN):$(PATH)
    
    ME_COM_COMPILER       ?= 1
    ME_COM_LIB            ?= 1
    ME_COM_MATRIXSSL      ?= 0
    ME_COM_MBEDTLS        ?= 1
    ME_COM_NANOSSL        ?= 0
    ME_COM_OPENSSL        ?= 0
    ME_COM_OSDEP          ?= 1
    ME_COM_SSL            ?= 0
    ME_COM_VXWORKS        ?= 0
    
    ME_COM_OPENSSL_PATH   ?= "/usr/local/openssl"

    修改2:自定义代码的编译

    在 goahead-linux-arm-default.mk 文件中添加对自定义程序 m283-webs 的编译支持

    #
    #    m283-webs.o
    #    47
    DEPS_47 += $(BUILD)/inc/goahead.h
    DEPS_47 += $(BUILD)/inc/js.h
    
    $(BUILD)/obj/m283-webs.o: 
        m283-webs/m283-webs.c $(DEPS_47)
        @echo '   [Compile] $(BUILD)/obj/m283-webs.o'
        $(CC) -c -o $(BUILD)/obj/m283-webs.o $(CFLAGS) $(DFLAGS) -D_FILE_OFFSET_BITS=64 -D_FILE_OFFSET_BITS=64 -DMBEDTLS_USER_CONFIG_FILE="embedtls.h" -DME_COM_OPENSSL_PATH=$(ME_COM_OPENSSL_PATH) $(IFLAGS) "-I$(ME_COM_OPENSSL_PATH)/include" m283-webs/m283-webs.c
    
    
    #
    #    m283-webs
    #    48
    DEPS_48 += $(BUILD)/bin/libgo.so
    DEPS_48 += $(BUILD)/.install-certs-modified
    DEPS_48 += $(BUILD)/obj/m283-webs.o
    
    ifeq ($(ME_COM_MBEDTLS),1)
        LIBS_48 += -lmbedtls
    endif
    ifeq ($(ME_COM_MBEDTLS),1)
        LIBS_48 += -lgoahead-mbedtls
    endif
    ifeq ($(ME_COM_MBEDTLS),1)
        LIBS_48 += -lmbedtls
    endif
    ifeq ($(ME_COM_OPENSSL),1)
        LIBS_48 += -lgoahead-openssl
    endif
    ifeq ($(ME_COM_OPENSSL),1)
    ifeq ($(ME_COM_SSL),1)
        LIBS_48 += -lssl
        LIBPATHS_48 += -L"$(ME_COM_OPENSSL_PATH)"
    endif
    endif
    ifeq ($(ME_COM_OPENSSL),1)
        LIBS_48 += -lcrypto
        LIBPATHS_48 += -L"$(ME_COM_OPENSSL_PATH)"
    endif
    LIBS_48 += -lgo
    ifeq ($(ME_COM_OPENSSL),1)
        LIBS_48 += -lgoahead-openssl
    endif
    ifeq ($(ME_COM_MBEDTLS),1)
        LIBS_48 += -lgoahead-mbedtls
    endif
    
    $(BUILD)/bin/m283-webs: $(DEPS_48)
        @echo '      [Link] $(BUILD)/bin/m283-webs'
        $(CC) -o $(BUILD)/bin/m283-webs $(LDFLAGS) $(LIBPATHS)  "$(BUILD)/obj/m283-webs.o" $(LIBPATHS_48) $(LIBS_48) $(LIBS_48) $(LIBS) $(LIBS)

     2.编译与测试

    复制 test.c 代码框架 到 m283-webs.c 来测试,后面按需修改

    make -f projects/goahead-linux-arm-default.mk

    在 build/linux-arm-default/bin 下生成了我们自定义程序的可执行文件 m283-webs ,将其拷贝到 nfs 的web调试目录

    通过上节可知,web 运行需要包含的文件如下所示

    在 web 中放入简单的 html 文件

    在目标板测试 运行正常

    GoAhead 常用操作实现

    GoActions 过程(旧版本使用的是GoForms,使用方式基本相同),绑定C函数为具体的URL链接,主要用于用于响应用户输入,更新设置或执行特定动作。

     一般过程:

    1.通过 websDefineAction 函数注册GoAction 函数,即绑定该 C 函数到 /action/test

    2.在 route.txt 中添加对应action路径 

    route uri=/action handler=action

    3.在html 文件中的表单中触发 http POST操作指定URL  /action/test

    这样当html 表单触发post时就会调用注册好的 action函数 test

    在新版本中,GoActions 过程的函数定义均可放在自定义程序中,下面是 m283-webs.c  goaction过程的实现部分代码

    m283-webs.c

    MAIN(goahead, int argc, char **argv, char **envp)
    {
        char    *argp, *home, *documents, *endpoints, *endpoint, *route, *auth, *tok, *lspec;
        int     argind, duration;
    
    #if WINDOWS
        if (windowsInit() < 0) {
            return 0;
        }
    #endif
        route = "route.txt";
        auth = "auth.txt";
        duration = 0;
    
        // 命令行解析
        for (argind = 1; argind < argc; argind++) {
            argp = argv[argind];
            if (*argp != '-') {
                break;
    
            } else if (smatch(argp, "--auth") || smatch(argp, "-a")) {
                if (argind >= argc) usage();
                auth = argv[++argind];
    
    #if ME_UNIX_LIKE && !MACOSX
            } else if (smatch(argp, "--background") || smatch(argp, "-b")) {
                websSetBackground(1);
    #endif
    
            } else if (smatch(argp, "--debugger") || smatch(argp, "-d") || smatch(argp, "-D")) {
                websSetDebug(1);
    
            } else if (smatch(argp, "--duration")) {
                        if (argind >= argc) usage();
                        duration = atoi(argv[++argind]);
    
            } else if (smatch(argp, "--home")) {
                if (argind >= argc) usage();
                home = argv[++argind];
                if (chdir(home) < 0) {
                    error("Cannot change directory to %s", home);
                    exit(-1);
                }
            } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
                if (argind >= argc) usage();
                logSetPath(argv[++argind]);
    
            } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
                logSetPath("stdout:2");
    
            } else if (smatch(argp, "--route") || smatch(argp, "-r")) {
                route = argv[++argind];
    
            } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
                printf("%s
    ", ME_VERSION);
                exit(0);
    
            } else if (*argp == '-' && isdigit((uchar) argp[1])) {
                lspec = sfmt("stdout:%s", &argp[1]);
                logSetPath(lspec);
                wfree(lspec);
    
            } else {
                usage();
            }
        }
        documents = ME_GOAHEAD_DOCUMENTS;
        if (argc > argind) {
            documents = argv[argind++];
        }
        initPlatform();        // 平台初始化,注册信号处理函数
        if (websOpen(documents, route) < 0) // 初始化服务器
        {
            error("Cannot initialize server. Exiting.");
            return -1;
        }
    #if ME_GOAHEAD_AUTH        // 加载路径和鉴权配置文件
        if (websLoad(auth) < 0)
        {
            error("Cannot load %s", auth);
            return -1;
        }
    #endif
        logHeader();        // 打印web服务器基本信息
        if (argind < argc) {
            while (argind < argc) {
                endpoint = argv[argind++];    // 参数中指定了服务器的endpoint 如./goahead -v ./web/  192.168.10.111:80
                // WEB端口监听
                if (websListen(endpoint) < 0) {
                    return -1;
                }
            }
        } else {
            endpoints = sclone(ME_GOAHEAD_LISTEN);
            for (endpoint = stok(endpoints, ", 	", &tok); endpoint; endpoint = stok(NULL, ", 	,", &tok)) {
    #if !ME_COM_SSL
                if (strstr(endpoint, "https")) continue;
    #endif
                if (websListen(endpoint) < 0) {
                    wfree(endpoints);
                    return -1;
                }
            }
            wfree(endpoints);
        }
    
    #if ME_ROM && KEEP    // 采用web文件ROM化
        /*
            If not using a route/auth config files, then manually create the routes like this:
            If custom matching is required, use websSetRouteMatch. If authentication is required, use websSetRouteAuth.
         */
        websAddRoute("/", "file", 0);
    #endif
    #ifdef GOAHEAD_INIT
        /*
            Define your init function in main.me goahead.init, or
            configure with DFLAGS=GOAHEAD_INIT=myInitFunction
         */
        {
            extern int GOAHEAD_INIT();
    
            if (GOAHEAD_INIT() < 0) {
                exit(1);
            }
        }
    #endif
    
        websDefineHandler("test", testHandler, 0, 0, 0);    // 定义一个请求处理程序
        websAddRoute("/test", "test", 0);
    #if ME_GOAHEAD_LEGACY
        // 表示对 /goform 的请求都交给 websFormHandler 函数处理。函数的参数列表如下
        websUrlHandlerDefine("/legacy/", 0, 0, legacyTest, 0);    // 设置form方式调用时候的文件位置
    //    websFormDefine(T("odbc_form_web_login"), odbc_form_web_login);    // 定义form方式调用接口函数字符对应的函数名称
    #endif
    #if ME_GOAHEAD_JAVASCRIPT
        websDefineJst("aspTest", aspTest);        // 定义一个js本地函数
        websDefineJst("bigTest", bigTest);
    #endif
        websDefineAction("test", actionTest);    // goAction定义,在asp文件中调用C函数
        websDefineAction("sessionTest", sessionTest);
        websDefineAction("showTest", showTest);
    
        websDefineAction("led", on_led_set);
        websDefineAction("buzzer", on_buzzer_set);
    
    #if ME_GOAHEAD_UPLOAD && !ME_ROM
        websDefineAction("uploadTest", uploadTest);
    #endif
    
    
    #if ME_UNIX_LIKE && !MACOSX
        /*
            Service events till terminated
         */
        if (websGetBackground()) {
            if (daemon(0, 0) < 0) {
                error("Cannot run as daemon");
                return -1;
            }
        }
    #endif
    
        if (duration) {
            printf("Running for %d secs
    ", duration);
            websStartEvent(duration * 1000, (WebsEventProc) exitProc, 0);
        }
        websServiceEvents(&finished);
        logmsg(1, "Instructed to exit
    ");
        websClose();
    
    #if WINDOWS
        windowsClose();
    #endif
        return 0;
    }
    
    
    static void actionTest(Webs *wp)
    {
        cchar    *name, *address;
    
        name = websGetVar(wp, "name", NULL);
        address = websGetVar(wp, "address", NULL);
        websSetStatus(wp, 200);
        websWriteHeaders(wp, -1, 0);
        websWriteEndHeaders(wp);
        websWrite(wp, "<html><body><h2>name: %s, address: %s</h2></body></html>
    ", name, address);
        websFlush(wp, 0);
        websDone(wp);
    }
    
    
    // led控制
    static void on_led_set(Webs *wp)
    {
        // get the input value in query stream
        char *io_val;
    
        io_val = websGetVar(wp, "val_led", NULL);
        if(io_val)
            system("echo 1 > /sys/class/leds/led-err/brightness");
        else
            system("echo 0 > /sys/class/leds/led-err/brightness");
    }
    
    // 蜂鸣器控制
    static void on_buzzer_set(Webs *wp)
    {
        char *io_val;
    
        io_val = websGetVar(wp, "val_buz", NULL);
        if(io_val)
            system("echo 1 > /sys/class/leds/beep/brightness");
        else
            system("echo 0 > /sys/class/leds/beep/brightness");
    }

    默认首页 index.html 添加 test 页面链接

    <html><head><title>index.html</title></head>
    <body>Hello /index.html</body>
    <p>Link to reload <a href="index.html">this page</a></p>
    <p>Link to <a href="/action/logout">log out</a></p>
    <p>Link to <a href="test.html">test.html</a></p>
    </html>

    测试的网页 test.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>test.html</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>Please log in</p>
        <form action=/action/test method="post">
            <table>
            <tr><td>账号:</td><td><input type="text" name="name"></td></tr>
            <tr><td>密码:</td><td><input type="password" name="address"></td></tr>
            <tr><td><input type="submit" name="submit" value="submit"></td>
                <td><input type="reset" value="reset"></td></tr>
            </table>
        </form>
        
        <br />
        <p align="left"><b> 蜂鸣器控制示例</p>
        <form id="gpio-buzzer" action="/action/buzzer" method="post">
        <input type="hidden" name="lab_buzzer" value="buzzer" />
            <table>
                <tr>
                    <td width=100>
                        BUZZER</td>
                    <td width=100>
                        <input type="checkbox" name="dir_buz" checked disabled title="out" />out</td>
                    <td width=100>
                        <input type="checkbox" name="val_buz" /></td>
                    <td width=100><input type="submit" value="set" /></td>
                </tr>
            </table>
        </form>
        
        <br />
        <p align="left"><b> LED控制示例</p>
        <form id="gpio-led" action="/action/led" method="post">
        <input type="hidden" name="lab_led" value="led" />
            <table>
                <tr>
                    <td width=100>
                        BUZZER</td>
                    <td width=100>
                        <input type="checkbox" name="dir_led" checked disabled title="out" />out</td>
                    <td width=100>
                        <input type="checkbox" name="val_led" /></td>
                    <td width=100><input type="submit" value="set" /></td>
                </tr>
            </table>
        </form>
        
        <script type="text/javascript">
        function loadXMLDoc()
        {
            var xmlhttp;
            if (window.XMLHttpRequest)
              {// code for IE7+, Firefox, Chrome, Opera, Safari
                  xmlhttp=new XMLHttpRequest();
              }
            else
              {// code for IE6, IE5
                  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
              }
            xmlhttp.onreadystatechange=function()
              {
                  if (xmlhttp.readyState==4 && xmlhttp.status==200)
                {
                    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
                    }
              }
            xmlhttp.open("GET","action/test",true);
            xmlhttp.send();
        }
        </script>
        
        <div id="myDiv"><h2>需要刷新的局部内容</h2></div>
        <button type="button" onclick="loadXMLDoc()">通过 AJAX 实现局部刷新</button>
        
        <p align="left"><b> &copy; 2019 HTGD Co.,Ltd.</b> <a href="http://www.htgd.com.cn">公司主页</a></p>
    </body>
    </html>

    每次重新编译之后,拷贝 m283-webs 可执行文件到测试nfs文件夹中

    目标机 挂载nfs

    运行 ./m283-webs -v /web/

    在浏览器输入 192.168.1.124  点击test.html链接

    或直接输入 192.168.1.124/test.html

    显示效果

    测试 goaction 交互

    填写内容 点击 submit,web 返回正常

    指示灯、蜂鸣器等web操作目标板硬件,测试正常;

    至此完成了 web 的部分内容交互,但该交互的页面刷新时整个页面的刷新,非常不方便;

    下一节实现部分页面刷新数据交互 Embedded Javascript,在网页上为 Ajax 技术。

  • 相关阅读:
    Mysql:为什么用limit时,offset很大会影响性能
    [解决方案]未能找到路径“~in oslyncsc.exe”的一部分
    [经验分享]NuGet发布自己的Dll(类库包)
    [解决方案]使用百度富文本编辑器,编辑显示不了内容
    [解决方案]未能加载文件或程序集
    [经验分享]WebApi+SwaggerUI 完美展示接口
    [经验分享]Linux网络连接-VMware+CentOS 7
    [经验分享]WebAPI中返回类型JsonMessage的应用
    [解决方案]WebAPI+SwaggerUI部署服务器后,访问一直报错的问题
    [解决方案] 当 IDENTITY_INSERT 设置为 OFF 时
  • 原文地址:https://www.cnblogs.com/silencehuan/p/10975774.html
Copyright © 2020-2023  润新知