HelloX操作系统应用编程指南

HelloX应用开发概述

可以通过三种方式,在HelloX操作系统基础上开发应用:

1.        以内部命令方式实现应用,直接编译链接到HelloX的内核shell中。这时候应用代码的执行上下文,是shell线程的上下文。应用程序代码不会单独成为一个独立的线程;

2.        以外部命令方式实现应用。直接编译链接到HelloX的内核中,通过shell来启动应用。这时候的应用,内核会创建一个独立的线程来承载;

3.        以外部应用方式实现应用。应用代码单独编译链接,完成后存放在安装了HelloX操作系统的计算机存储设备中。在shell下,使用loadapp命令,加载可执行的应用模块。这种方式下,应用代码也是在一个独立的线程中执行的。需要注意的是,在这种方式下,应用代码只能调用HelloX SDK提供的API接口函数和C库函数。

本文主要对第一种和第二种实现方式进行说明。

以内部命令方式实现应用

内部命令采用映射表的方式,使系统功能的添加和删除变得比较容易。比如要添加一个功能,只需要写一个处理函数,然后在HelloX的内部命令射表内添加一个项目即可。下面我们通过一个示例来说明如何往系统中添加新的功能。

第一步:假设新增的功能命令为mycommand,首先编写一个功能函数,可以直接在SHELL.CPP文件中添加,也可以通过另外的模块实现,然后在SHELL.CPP中,包含实现的命令函数的头文件。假设mycommand命令的实现函数如下。

VOID mycommand(LPSTR)

{

ChangeLine();

PrintLine("Hello,World!");

ChangeLine();

}

该函数的功能十分简单,打印出“Hello,World!”字符串,这也是大多数编程语音的一个入门示例。

第二步:把该命令字符串和命令函数添加到内部命令列表中,并更改CMD_OBJ_NUM宏为原来的值加一,因为新增加了一个内部命令。代码如下(黑体部分是修改内容):

//#define CMD_OBJ_NUM  21

#defineCMD_OBJ_NUM  22

__CMD_OBJ  CmdObj[CMD_OBJ_NUM] = {

{"version"  ,   VerHandler},

{"memory"   ,   MemHandler},

{"sysinfo"  ,   SysInfoHandler},

{"sysname"  ,   SysNameHandler},

{"help"     ,   HlpHandler},

{"cpuinfo"  ,   CpuHandler},

{"support"  ,   SptHandler},

{"runtime"  ,   RunTimeHandler},

{"test"     ,   TestHandler},

{"untest"   ,   UnTestHandler},

{"memview"  ,   MemViewHandler},

{"ktview"   ,   KtViewHandler},

{"ioctrl"   ,   IoCtrlApp},

{"sysdiag"  ,   SysDiagApp},

{"loadapp"  ,   LoadappHandler},

{"gui"      ,   GUIHandler},

{"reboot"   ,   Reboot},

{"poff"     ,   Poweroff},

{"cls"      ,   ClsHandler},

    {“mycommand”,   mycommand}

};

第三步:重新编译连接(rebuild)整个操作系统核心,并重新制作引导盘引导系统。成功启动后,在命令行提示符下,输入mycommand并回车,就可以看到mycommand的输出了。

需要注意的是,内部命令是直接在shell线程上下文中被调用的,没有自己独立的执行环境。因此只适合于实现较为简单的功能。

以外部命令方式实现应用

外部命令则会有独立的执行上下文,被内核以独立线程方式加载运行。因此,外部命令的功能非常强大,可以进一步以子命令的方式,实现更进一步的功能。比如,HelloX的网络诊断功能,就是以外部命令方式实现的。用户在shell界面下,输入network后回车,即可进入network诊断命令。这时候系统提示符会改变。在network命令下,输入help命令,可以看到该命令模式下所有可用的子命令,如下图:

其中iflist,ping等就是network应用下的子命令。在执行子命令的时候,用户可以指定参数,HelloX会以一种统一的方式,把用户指定的参数,传递给命令处理函数。

下面以network诊断外部命令的实现为例,说明外部命令的实现方式。

第一步:编写外部命令的入口处理函数。

以network命令为例,要编写类似下列形式的处理函数:

DWORD networkEntry(LPVOID p)

{

return Shell_Msg_Loop(NETWORK_PROMPT_STR,CommandParser,QueryCmdName);

}

具体的处理函数的实现,就是开发者大显神通的地方。比如要实现子命令,则需要定义一些子命令映射列表等信息。在上面的实现中,是一个消息处理循环,根据用户的输入,来调用特定的子命令。

注意,外部命令下的子命令,既可以直接在外部命令的线程上下文中执行,也可以单独创建执行线程,取决于开发者的判断。

需要注意的是,外部命令的字命令处理函数,必须以下列格式来定义:

static DWORD ping(__CMD_PARA_OBJ* lpCmdObj)

{

__PING_PARAM     PingParam;

ip_addr_t        ipAddr;

int              count      = 3;   //Ping counter.

int              size       = 64;  //Ping packet size.

BYTE             index      = 1;

DWORD            dwRetVal   = SHELL_CMD_PARSER_FAILED;

__CMD_PARA_OBJ*  pCurCmdObj = lpCmdObj;

if(pCurCmdObj->byParameterNum<= 1)

{

return dwRetVal;

}

while(index <lpCmdObj->byParameterNum)

{

if(strcmp(pCurCmdObj->Parameter[index],"/c")== 0)

{

index++;

if(index>= lpCmdObj->byParameterNum)

{

break;

}

count    = atoi(pCurCmdObj->Parameter[index]);

}

elseif(strcmp(pCurCmdObj->Parameter[index],"/l") == 0)

{

index++;

if(index>= lpCmdObj->byParameterNum)

{

break;

}

size   = atoi(pCurCmdObj->Parameter[index]);

}

else

{

ipAddr.addr= inet_addr(pCurCmdObj->Parameter[index]);

}

index ++;

}

if(ipAddr.addr != 0)

{

dwRetVal    = SHELL_CMD_PARSER_SUCCESS;

}

PingParam.count      = count;

PingParam.targetAddr =ipAddr;

PingParam.size       = size;

//Call ping entry routine.

ping_Entry((void*)&PingParam);

return dwRetVal;

}

子命令处理函数必须返回一个DWORD类型的值,用来表示子命令的执行情况,比如成功或者是失败。同时,子命令处理函数的参数,也必须是__CMD_PARA_OBJ* 类型。这是个内部定义的参数传递数据结构,如下:

typedef struct tag__CMD_PARA_OBJ

{

BYTE        byParameterNum;         //How many parameters  followed.

WORD        wReserved;

CHAR*       Parameter[CMD_PARAMETER_COUNT];

}__CMD_PARA_OBJ;

byParameterNum指明了这个结构体中包含的参数个数,而Parameter则是一个字符串数组,包含了每个字符串参数的首地址。这与标准的C入口函数main(intargc,char* argv[])的参数是一致的。其中byParameterNum与argc对应,而Parameter则与argv数组对应。需要注意的是,数组中的第一个参数,就是子命令字符串本身。这与C的argv数组中,第一个是应用程序文件名字符串的情况一致。

子命令函数就可以通过分析__CMD_PARA_OBJ对象,来获取每个参数。

第二步:在外部命令数组中,增加入口函数信息。

外部命令数组在kernel/shell/extcmd.c文件中,在这个数组中增加一项,如下:

__EXTERNAL_COMMAND ExtCmdArray[] = {

{"fs",NULL,FALSE,fsEntry},

{"fdisk",NULL,FALSE,fdiskEntry},

{"hedit",NULL,FALSE,heditEntry},

{"fibonacci",NULL,FALSE,Fibonacci},

{"hypertrm",NULL,FALSE,Hypertrm},

{"hyptrm2",NULL,FALSE,Hyptrm2},

#if defined(__CFG_NET_IPv4) || defined(__CFG_NET_IPv6)

{"network",NULL,FALSE,networkEntry},

#endif

//Add your externalcommand/application entry here.

//{"yourcmd",NULL,FALSE,cmdentry},

//The last entry of thisarray must be the following one,

//to indicate theterminator of this array.

{NULL,NULL,FALSE,NULL}

};

数组元素的第一个参数,就是定义的外部命令字符串。用户在shell下,输入该字符串,shell就会以这个字符串为索引,搜索这个数组,找到对应的执行函数,创建一个内核线程并执行。数组元素中的最后一个参数,就是对应的外部命令入口函数。数组元素的第二和第三个参数,主要是指明了外部命令的入口参数,以及是否已阻塞方式执行。如果设置为TRUE,则以非阻塞方式执行,也就是与shell一起并行执行。否则的话,shell会阻塞,等待外部命令执行完毕后,再继续执行。一般设置为FALSE,这样可以确保shell能够及时的释放掉相关资源。

第三步:在帮助数组中增加一行,确保外部命令能够在help输出中可见。

在shell下,用户输入help命令,可以列出系统中所有可用的内部和外部命令。为了确保新增加的外部命令在help命令中可见,需要在下列数组(kernel/shell/shell1.c)中增加相关的帮助描述和输出信息:

//Handler for help command.

DWORD HlpHandler(__CMD_PARA_OBJ* pCmdParaObj)           //Command 'help' 's handler.

{

LPSTR strHelpTitle   = "   The following commands are available currently:";

LPSTR strHelpVer     = "   version      : Print out theversion information.";

LPSTR strHelpMem     = "   memory       : Print out currentversion's memory layout.";

LPSTR strHelpSysInfo ="    sysinfo      : Print out the system context.";

LPSTR strSysName     = "   sysname      : Change the systemhost name.";

LPSTR strHelpHelp    = "   help         : Print out thisscreen.";

LPSTR strSupport     = "   support      : Print out technicalsupport information.";

LPSTR strTime        = "    time        : Show system date and time.";

LPSTR strRunTime     = "   runtime      : Display the totalrun time since last reboot.";

LPSTR strIoCtrlApp   ="    ioctrl       : Start IO control application.";

LPSTR strSysDiagApp  = "   sysdiag      : System or hardwarediag application.";

LPSTR strFsApp       = "    fs          : File system operating application.";

LPSTR strFdiskApp    = "   fdisk        : Hard disk operating application.";

LPSTR strNetApp      = "    network     : Network diagnostic application.";

LPSTR strLoadappApp  = "   loadapp      : Load applicationmodule and execute it.";

LPSTR strGUIApp      = "    gui         : Load GUI module and enter GUI mode.";

#ifdef __CFG_APP_JVM

LPSTR strJvmApp      = "    jvm         : Start Java VM to run Java Application.";

#endif  //__CFG_APP_JVM

LPSTR strReboot      = "    reboot      : Reboot the system.";

LPSTR strCls         = "    cls         : Clear the whole screen.";

PrintLine(strHelpTitle);              //Print out the help informationline by line.

PrintLine(strHelpVer);

PrintLine(strHelpMem);

PrintLine(strHelpSysInfo);

PrintLine(strSysName);

PrintLine(strHelpHelp);

PrintLine(strSupport);

PrintLine(strTime);

PrintLine(strRunTime);

PrintLine(strIoCtrlApp);

PrintLine(strSysDiagApp);

PrintLine(strFsApp);

PrintLine(strNetApp);

PrintLine(strFdiskApp);

PrintLine(strLoadappApp);

PrintLine(strGUIApp);

#ifdef __CFG_APP_JVM

PrintLine(strJvmApp);

#endif //__CFG_APP_JVM

PrintLine(strReboot);

PrintLine(strCls);

return S_OK;

}

需要注意的是,不仅仅要增加一个LPSTR(char*)类型的字符串定义,还要在下面增加对应的PrintLine输出,否则不会有信息书出来。

完成上述三个步骤之后,重新编译HelloX内核,然后用最新的内核引导计算机。进入shell后,执行help命令,应该可以看到新增加的外部命令了。输入对应的外部命令字符串,即可看到外部命令的执行结果。

实际上,外部命令的复杂之处,主要还是在于如何处理用户输入,以及如何根据用户的输入,调用对应的子命令处理函数。HelloX实现了很多外部命令,比如本文讲到的network命令,系统诊断sysdiag命令,输入输出控制ioctrl命令,以及文件系统操作命令fs等。开发者可以在这些外部实现的基础上,利用已有的框架,修改特定的部分即可。比如,对于外部命令的入口函数,可以直接在现有的基础上,修改一下函数名。对于子命令处理函数,可以根据需要,进行修改或定义。完成后,要增加到本地子命令映射数组中。比如network命令的子命令映射数组如下:

static struct __NETWORK_CMD_MAP{

LPSTR                lpszCommand;

DWORD               (*CommandHandler)(__CMD_PARA_OBJ*);

LPSTR                lpszHelpInfo;

}SysDiagCmdMap[] = {

{"iflist",     iflist,   "  iflist   : Show all network interface(s) insystem."},

{"ping",       ping,      " ping     : Check a specifiedhost's reachbility."},

{"route",      route,    "  route    : List all route entry(ies) insystem."},

{"exit",       _exit,      " exit     : Exit theapplication."},

{"help",       help,      " help     : Print out thisscreen."},

{"showint",    showint,  "  showint  : Display ethernet interface's statisticsinformation."},

{"assoc",      assoc,    "  assoc    : Associate to a specified WiFiSSID."},

{"scan",       scan,      " scan     : Scan WiFi networks andshow result."},

{"setif",      setif,    "  setif    : Set IP configurations to a giveninterface."},

{NULL,                 NULL,      NULL}

};

数组元素的第一个参数,就是子命令字符串,第二个参数,是该子命令的处理函数。最后一个字符串信息,则是该子命令的帮助信息。在外部命令提示符下,输入help,就会显示出所有可用的子命令帮助信息。

开发者可以在此基础上,根据自己的实现,修改或删除特定的映射表项即可。

需要注意的是,为了确保整体代码的整洁,建议外部命令的组织,遵循下列原则:

1.   所有新增外部命令的代码,放在一个新创建的代码文件中,不要与现有的shell源文件放在一起;

2.   新增加的外部命令源文件,放在shell目录下。

物联网操作系统HelloX应用编程指南的更多相关文章

  1. 物联网操作系统HelloX开发者入门指南

    HelloX开发者入门指南 HelloX是聚焦于物联网领域的操作系统开发项目,可以通过百度搜索"HelloX",获取详细信息.当前开发团队正在进一步招募中,欢迎您的了解和加入.如果 ...

  2. 基于物联网操作系统HelloX的智慧家庭体系架构

    基于物联网操作系统HelloX的智慧家庭体系架构 智慧家庭是物联网的一个分支应用,是一个被广泛认同的巨大IT市场空间.目前市场上已经有很多针对智慧家庭的产品或解决方案,但与移动互联网不同,智慧家庭至今 ...

  3. 物联网操作系统HelloX V1.80测试版发布

    经过HelloX开发团队近半年的努力,在HelloXV1.79版本基础上,增加许多功能特性,并对V1.79版本的一些特性进行了进一步优化之后,正式形成HelloX V1.80测试版本.经相对充分的测试 ...

  4. 物联网操作系统HelloX V1.77(beta)版本发布

    物联网操作系统HelloX V1.77发布 经过近半年的努力,物联网操作系统HelloX V1.77版本正式完成,源代码已上载到github(github.com/hellox-project/Hel ...

  5. 物联网操作系统HelloX V1.79发布公告

    经过HelloX开发团队近半年的努力,在HelloX V1.78版本基础上,增加许多功能特性,并对V1.78版本的一些特性进行了进一步优化之后,正式形成HelloX V1.79测试版本.经相对充分的测 ...

  6. 物联网操作系统HelloX V1.78测试版正式发布

    经过HelloX开发团队近四个月的努力,在HelloX V1.77版本基础上,增加许多功能特性,并对V1.77版本的一些特性进行了进一步优化之后,正式形成HelloX V1.78测试版本,经相对充分的 ...

  7. 物联网操作系统HelloX已成功移植到MinnowBoard MAX开发板上

    在HelloX开发团队的努力下,以及Winzent Tech公司(总部在瑞典斯德哥尔摩)的支持下,HelloX最新版本V1.78已成功移植到MinnowBoard MAX开发板上.相关源代码已经发布到 ...

  8. 物联网操作系统HelloX开发人员入门指南

    HelloX开发人员入门指南 HelloX是聚焦于物联网领域的操作系统开发项目,能够通过百度搜索"HelloX".获取具体信息. 当前开发团队正在进一步招募中,欢迎您的了解和添加. ...

  9. 高质量C++/C编程指南(林锐)

    推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐   2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐   20 ...

随机推荐

  1. Matlab中mat2cell的使用

    怎样用mat2cell将一个100*100的矩阵分成10个10*100的矩阵? 根据帮助中 c = mat2cell(x,m,n)应该这样写 mat2cell(x,[10 10 10 10 10 10 ...

  2. gcd,lcm,ext_gcd,inv

    Least Common Multiple http://acm.hdu.edu.cn/showproblem.php?pid=1019 #include<cstdio> int gcd( ...

  3. [设计模式] 3 创建者模式 builder

    转载http://blog.csdn.net/wuzhekai1985/article/details/6667467 建造者模式的定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不 ...

  4. JAVA数据源连接方式汇总

    最近在研究JAVA的数据源连接方式,学习的时候发现了一位同行写的文章,转载过来,留作记录! 一.问题引入 在java程序中,需要访问数据库,做增删改查等相关操作.如何访问数据库,做数据库的相关操作呢? ...

  5. ext3grep 恢复删除

    Linux ext2/ext3 文件删除恢复工具ext3grep安装使用 2010-08-23 18:03:10|  分类: 默认分类|举报|字号 订阅     一.           安装前系统环 ...

  6. 2013 Multi-University Training Contest 2 Balls Rearrangement

    先算出lcm(a,b),如果lcm>=n,则直接暴力解决:否则分段,求出0-lcm内的+0-n%lcm内的值. 再就是连续相同的一起计算!! #include<iostream> # ...

  7. 2013 ACM-ICPC长沙赛区全国邀请赛——A So Easy!

    这题在比赛的时候不知道怎么做,后来看了别人的解题报告,才知道公式sn=(a+sqrt(b))^n+(a-sqrt(b))^n; 具体推导 #include<iostream> #inclu ...

  8. lintcode:Matrix Zigzag Traversal 矩阵的之字型遍历

    题目: 矩阵的之字型遍历 给你一个包含 m x n 个元素的矩阵 (m 行, n 列), 求该矩阵的之字型遍历. 样例 对于如下矩阵: [ [1, 2, 3, 4], [5, 6, 7, 8], [9 ...

  9. [mock]7月25日

    1. 将一个数组分成左右两部分,使得右边的某个连续子段和减去左边的某个连续字段和最小[7,8,9,|3,5,-1] sum right - sum left minimal 想到左右分一刀,O(n), ...

  10. 【Linux高频命令专题(10)】mv

    概述 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 命令格式 mv [选项] 源文件或目 ...