This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C129ENCPDT:TI-RTOS:具有 cgi 函数的服务器

Guru**** 2524550 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/989739/tm4c129encpdt-ti-rtos-server-with-cgi-functions

器件型号:TM4C129ENCPDT

您好!

我有一个具有 cgi 函数的服务器。 如果调用了 cgi 函数、我会发送 html 代码、该函数以1结尾。

现在、我想在任务中发送 html 代码。 遗憾的是、它不起作用。 请允许有人告诉我、为什么我很感谢任何帮助

static int mainPage_Update(SOCKET htmlSock, int ContentLength, char *pArgs )
{
	Mailbox_post(mailboxServerHandle, &htmlSock, BIOS_NO_WAIT);

	//sendMainPage(htmlSock);

	return 1;
}


void serverTask(void)
{
	SOCKET msg;

	while(1)
	{
		Mailbox_pend(mailboxServerHandle, &msg, BIOS_WAIT_FOREVER);
        sendMainPage(msg);
	}
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     是否使用 efs_CreateFile 将 C 函数入口点与 CGI 文件关联。 请参阅 NDK API 指南中的 E.1.3节。  https://www.ti.com/lit/pdf/spru524

    示例:  

    efs_CreateFile ("sample.cgi"、0、(unsigned char *) cgiSample);

    另请参阅此帖子、其中 Todd 提供了一个创建 HTTP 服务器的示例、包括使用 CGI 函数。  

    https://e2e.ti.com/support/microcontrollers/other/f/other-microcontrollers-forum/947315/faq-tm4c1294kcpdt-do-you-have-an-example-of-a-http-server-on-a-tivac-device-running-ti-rtos-sys-bios

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    感谢您的回答。 当然会执行.cgi 函数、如果我直接从 cgi 函数发送我的 html 文本、则一切都正常。

    现在、我不想在 cgi 函数中发送 html 文本、而是从任务中发送。 我稍微更改了 http 服务器示例、以便您了解我的计划。

    /*
     * Copyright (c) 2015, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *  ======== empty.c ========
     */
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <xdc/cfg/global.h>
    
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Mailbox.h>
    
    /* TI-RTOS Header files */
    
    #include <ti/drivers/GPIO.h>
    
    
    /* Board Header file */
    #include "Board.h"
    
    #include <ti/ndk/inc/netmain.h>
    #include "index_withCGI.h"
    #include "greetings.h"
    #include "chip.h"
    
    #define TASKSTACKSIZE   1024
    
    Task_Struct task0Struct;
    Char task0Stack[TASKSTACKSIZE];
    
    
    
    Void sendWebsite(SOCKET* s)
    {
        Char buf[200];
        static UInt scalar = 0;
    
        if (scalar == 0) {
            scalar = 1000000u / Clock_tickPeriod;
        }
        httpSendStatusLine(s, HTTP_OK, CONTENT_TYPE_HTML);
        httpSendClientStr(s, CRLF);
        httpSendClientStr(s, "<html><head><title>SYS/BIOS Clock Time</title></head><body><h1>Time</h1>\n");
        System_sprintf(buf, "<p>Up for %d seconds</p>\n", ((unsigned long)Clock_getTicks() / scalar));
        httpSendClientStr(s, buf);
        httpSendClientStr(s, "</table></body></html>");
    }
    
    Int getTime(SOCKET s, int length)
    {
    	Mailbox_post(mailbox0, &s, BIOS_NO_WAIT);
        return (1);
    }
    
    Void AddWebFiles(Void)
    {
        //Note: both INDEX_SIZE and INDEX are defined in index.h
        efs_createfile("index.html", INDEX_SIZE, (UINT8 *)INDEX);
        efs_createfile("getTime.cgi", 0, (UINT8 *)&getTime);
        efs_createfile("greetings.html", GREETINGS_SIZE, (UINT8 *)GREETINGS);
        efs_createfile("chip.jpg", CHIP_SIZE, (UINT8 *)CHIP);
    }
    
    Void RemoveWebFiles(Void)
    {
        efs_destroyfile("index.html");
        efs_destroyfile("getTime.cgi");
        efs_destroyfile("greetings.html");
        efs_destroyfile("chip.jpg");
    }
    
    /*
     *  ======== heartBeatFxn ========
     *  Toggle the Board_LED0. The Task_sleep is determined by arg0 which
     *  is configured for the heartBeat Task instance.
     */
    Void heartBeatFxn(UArg arg0, UArg arg1)
    {
    	SOCKET msg;
    
        while (1)
        {
        	Mailbox_pend(mailbox0, &msg, BIOS_WAIT_FOREVER);
        	System_printf("msg: %d\n", msg);System_flush();
        	sendWebsite(msg);
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        Task_Params taskParams;
        /* Call board init functions */
        Board_initGeneral();
        Board_initEMAC();
        Board_initGPIO();
    
    
        /* Construct heartBeat Task  thread */
        Task_Params_init(&taskParams);
        taskParams.arg0 = 1000;
        taskParams.stackSize = TASKSTACKSIZE;
        taskParams.stack = &task0Stack;
        taskParams.priority = 1;
        Task_construct(&task0Struct, (Task_FuncPtr)heartBeatFxn, &taskParams, NULL);
    
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

    很遗憾、浏览器无法识别任何已发送的数据。
    那么、如何将套接字传输到任务并在任务中发送 html 代码呢?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

      当您在浏览器上单击 getTime.cgi 时,getTime()函数是否解除了 mailbox0句柄的阻断? 换言之,如果在 SendWebsites()中放置一个断点,它是否到达那里?

     我不是 TI-RTOS EFS_CreateFile 的专家。 我只是不确定您的操作是否是使用任务插入 CGI 函数的正确方法。 如果您只需切换 GPIO 引脚,而不是在 BeatFxn 中调用 sendWebsites(),该怎么办? 引脚是否会切换? 我只是想隔离这个问题。  

     我还假设您在.cfg 文件中创建具有正确消息大小和消息数量的邮箱对象。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    邮箱大小为4字节。
    我可以确认 Mailbox_post 函数解锁了 Mailbox_pend 并且任务正在运行。

    问题在于是否可以在任务中发送 html 页面?
    我在这里再也找不到比这里更好的了。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     有关详细信息、请参阅 NDK API 用户指南。  在进行一些搜索后、我可以找到这种情况、并解释如何在任务中调用 cgi 函数、而该任务可能不像您所做的那样工作。  http://software-dl.ti.com/simplelink/esd/simplelink_msp432e4_sdk/2.30.00.14/docs/ndk/NDK_API_Reference.html#e-web-programming-with-the-http-server

     

    E 使用 HTTP 服务器进行 Web 编程

    从嵌入式网络设备获取信息的最简单方法是通过 Web 服务器。 HTTP 服务器从 NDK 软件包的操作系统适配层中包含的嵌入式文件系统(EFS)提取文件。 这些文件可以编译到应用程序中、位于网络文件系统、基于内存的文件系统或连接到 DSP 的物理磁盘上。 NDK HTTP 服务器通过 EFS 应用程序接口访问文件、该接口可移植到所需的任何文件系统。 服务器支持 HTTP/1.0协议。

    通用网关接口(CGI)程序在 Web 服务器上执行、并处理用户的输入。 它们可用作设备上运行的服务的接口。 为 NDK 编写 CGI 程序相对简单、只需要几个特定的函数。 可以编写一个单一 CGI 接口函数来支持 HTTP POST 请求和 GET 请求。

    CGI 程序是从单个 C 可调用入口点(或 CGI 函数)构建的。 每个 CGI 函数都在其自己的独立任务线程上调用。 任务线程的创建优先级为 OS_TASKPRINORM、栈大小为 OS_TASKSTKHIGH。 请注意、对同一 CGI 函数的连续调用将不会位于同一任务线程中。 因此、CGI 函数无法从一个调用共享套接字到下一个调用。 一般而言、CGI 函数中没有持久性数据。

    此外、CGI 函数的文件检测完全是在文件扩展名上完成的。 如果文件以.cfg (不区分大小写)结尾、则文件的发布或获取将导致对映射到该文件名的 CGI 函数的调用。 不允许对非 CGI 文件进行 POST 调用。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     我完成了更多搜索。 我想知道你是否补充  fdOpenSession() and fdCloseSession() to your task creation will make a difference. Please refer to section 3 of the TI-RTOS NDK API user's guide for details. https://software-dl.ti.com/simplelink/esd/simplelink_msp432e4_sdk/2.30.00.14/docs/ndk/NDK_API_Reference.html. Below is a snippet of the notes. Here you will see several ways to handle the file descriptor. 

    3个套接字和流 IO API

    本章介绍套接字和文件 API 函数。

    3.1文件描述符环境

    在大多数嵌入式操作系统环境中、对文件描述符的支持差异很大。 在大多数情况  下,只提供最基本的功能,并使用常用的保留名称(read()、write()、close()等)提供经过修整的支持函数。

    由于该堆栈支持标准套接字接口函数、并且这些函数需要文件描述符支持、因此该堆栈提供了自己的小型文件系统。 本节介绍文件系统的基本机制。

    3.1.1组织

    堆栈代码内部的基本构建块是对象句柄。 在堆栈内部、套接字和管道都由对象句柄寻址。 但是、在应用程序级别、套接字和管道被视为文件描述符。 文件描述符包含附加状态信息、允许根据套接字活动阻止和解除阻止任务。

    堆栈 API 通过向本机操作环境中添加抽象的文件描述符层来支持文件描述符的使用。 该层实现了标准套接字和文件 IO 功能。 堆栈的工作方式是将文件描述符会话与每个调用方的线程(或在本术语中,任务)相关联。 在此系统中、每个任务都有自己的文件描述符会话。 当任务需要阻止挂起的网络活动时、使用文件描述符会话。

    请注意,尽管文件描述符可以用于诸如  select()之类的经典函数,但在此实现中,它们仍然是句柄,而不是整数。 为了实现兼容性、网络应用程序必须使用 NDK 头文件、并针对错误条件(非-1)使用 INVALID_Socket、并且在检查有效性时不要将套接字比较为<0。

    3.1.2初始化文件系统环境

    要使用栈提供的文件系统和套接字函数、任务必须首先分配文件描述符表(称为文件描述符会话)。 这是通过调用文件描述符函数  fdOpenSession()在应用层实现的。

    当使用文件描述符 API 完成任务时,或当任务即将终止时,  调用函数 fdCloseSession()。

    3.1.2.1何时初始化文件描述符环境

    为了实现正确的堆栈操作、任务线程必须在调用任何与文件描述符相关的函数之前打开文件描述符会话、然后在完成后将其关闭。

    处理文件描述符会话的最简单方法是调用  TaskCreate(),它在内部处理文件描述符会话的打开和关闭。

    处理文件描述符会话的另一种方法是任务在文件会话启动时打开、并在会话完成时关闭。 例如:

    套接字任务:

    void socket_task(int IPAddr, int TcpPort) 
    {
        SOCKET s; 
    
        // Open the file session
        fdOpenSession(TaskSelf());
    
        < socket application code > 
    
        // Close the file session 
        fdCloseSession(TaskSelf()); 
    }

    另一种方法是用于创建套接字任务线程以打开子线程的文件描述符会话的任务。 请注意,父任务必须保证子任务的文件会话在子任务执行之前打开。 这是通过任务优先级或信标完成的、但可能会使任务创建变得复杂。 因此、这不是理想的方法。

    还可以允许子任务打开其自己的文件会话、但允许父任务监视其子任务并最终销毁它们。 在这里、父任务必须关闭它所破坏的子任务线程的文件会话。 然后、子任务在完成时会阻止、而不是终止其自己的线程。 以下示例说明了此概念:

    子套接任务:

    void child_socket_task(int IPAddr, int TcpPort) 
    {
        SOCKET s;
     
        // Open the file session 
        fdOpenSession(TaskSelf()); 
    
        < socket application code > 
    
        // We are done, but our parent thread will close 
        // our file session and destroy this task, so here 
        // we just yield. 
        TaskYield(); 
    }

    父任务函数如下所示:

    父任务函数:

    void create_child_task() 
    { 
        // Create System Tasks 
    
        // Create a child task 
        hChildTask = TaskCreate(&child_socket_task, ?); 
    } 
    
    void destroy_child_task() 
    { 
        // First close the child's file session 
        // (This will close all open files) 
        fdSessionClose(hChildTask); 
    
        // Then destroy the task 
        TaskDestroy(hChildTask); 
    }

    3.1.2.2自动初始化文件描述符环境

    对于使用 XGCONF 或*。cfg 配置文件配置应用程序的 TI-RTOS 内核用户、可以将对 fdOpenSession 和 fdCloseSession 的调用配置为自动调用。 这是通过设置以下配置参数实现的:

    var Global = xdc.useModule('ti.ndk.config.Global.xdc');
    Global.autoOpenCloseFD = true;

    将此参数设置为 true 会分别在 TI-RTOS 内核任务模块的 create hook 函数和 exit hook 函数中自动调用 fdOpenSession 和 fdCloseSession。

    请注意、Global.autoOpenCloseFD 参数仅支持从任务上下文(即从另一个正在运行的任务函数内)中创建的动态创建的任务。 在配置中静态创建的任务或在 main()或 Hwi 或 Swi 线程中动态创建的任务不支持此功能。