无忧启动论坛

标题: com口读取数据grub4dos编程 [打印本页]

作者: 2012goodbye    时间: 2013-6-13 15:32
标题: com口读取数据grub4dos编程
我因工作需要想自己编写一个能从com1,com2,com3,com4都能读取数据的grub4dos外部命令,不知道从什么地方下手??希望各位大大给点意见.....
Google,百度都找过,找到的基本上都是dos下的...,但本人又是新手一枚,不知道怎么移植。
作者: 不点    时间: 2013-6-13 18:28
对此技术,我也不太熟悉。不过,我参与了 grub4dos 的开发,所以,我能从 grub4dos 的角度,为您提供一些信息。

grub4dos 支持 16 位的程序,以及 32 位的程序。就是说,你有可能把你的 DOS 下的 16 位程序移植到 grub4dos 下,变成 grub4dos 的 16 位应用程序。你也可以把某个 32 位的程序(比如 for windows 或者 for linux 的程序)移植到 grub4dos 下,变成 grub4dos 的 32 位应用程序。

如果源代码比较短的话,你可以贴上来,等我有时间的话,我仔细瞧瞧,给您一个答复。


作者: 2012goodbye    时间: 2013-6-14 03:32
以下代码是网上找的DOS下的代码,帮忙看下怎么转换grub4dos代码。

/////////////////////////////////////////////////////////////
//COMRX.CPP  for asyn serial communication (only RX)
//edited by Xiong Guangming and Gong Jianwei
//Turbo C++3.0
/////////////////////////////////////////////////////////////
#include <stdio.h>
#include <dos.h>
#include <conio.h>

#define BUFFLEN 1024

void InitCOM();  //初始化串口
void OpenPort();  //打开串口
void ClosePort(); //关闭串口,释放串口资源
//新的中断函数,注意在TC2.0下,下面函数的...要去掉
void interrupt far  asyncint(...);
//中断向量:用于保存中断现场
void interrupt(*asyncoldvect)(...);

unsigned char Buffer[BUFFLEN];
int buffin=0;
int buffout=0;
//unsigned char ch;

//COM1产生的硬件中断号为IQR4,对应的中断向量为为0CH
//打开COM1
void OpenPort()
{
        unsigned char ucTemp;
        InitCOM();  //初始化串口

        //读入由参数给定的中断向量值,并将它作为中断函数的远地址
        asyncoldvect=getvect(0x0c);
        disable();       //关中断
        inportb(0x3f8);
        inportb(0x3fe);
        inportb(0x3fb);
        inportb(0x3fa);
        outportb(0x3fc,0x08|0x0b);
        outportb(0x3f9,0x01);
        ucTemp=inportb(0x21)&0xef;
        outportb(0x21,ucTemp);
        setvect(0x0c,asyncint);
        enable();       //开中断
}

//中断服务程序,从COM1接收数据
//注意在TC2.0下,下面函数的...要去掉
void interrupt far asyncint(...)
{
        //unsigned char ch;
        Buffer[buffin++] = inportb(0x3f8);// 读字符到缓冲区
        if (buffin >= BUFFLEN)  // 缓冲区满
                buffin=0;           // 指针复位
        outportb(0x20,0x20);
}

void ClosePort(void) //关闭中断
{
        disable();
        outportb(0x3f9,0x00);
        outportb(0x3fc,0x00);
        outportb(0x21,inportb(0x21)&0x10);
        enable();
        setvect(0x0c,asyncoldvect);
}

void InitCOM()// 对COM1串口初始化,设置串口参数
{

        outportb(0x3fb,0x80);  //将设置波特率
        /* 设置波特率,低位在前、高位在后;(部分波特率器参数如下)
     波特率    分频器H   分频器L
         ...
         4800       00        18H
         7200       00        10H
         9600       00        0CH
         ....         
  */
        outportb(0x3f8,0x0C);   //波特率为9600bps
        outportb(0x3f9,0x00);

        /*设置停止位、奇偶校验位、等
        D7:为1表示设置波特率;为0,其他;
        D6:为1,是,强迫在数据线上输出逻辑0;为0,则否;
        D5:1,校验位可变;0,不变;
        D4D3:×0,无校验位;01,奇校验位;11,偶校验位;
        D2:0,1个停止位;1,1.5个停止位;
        D1D0:00,5位数据位;01,6位数据位;10,7位数据位;11,8位数据位;
        */
        outportb(0x3fb,0x03);   //8个数据位,1个停止位、无奇偶校验

        outportb(0x3fc,0x08|0x0b);
        outportb(0x3f9,0x01);
}


unsigned char read_char(void)
{
        unsigned unch;
        if(buffout != buffin)
        {
                unch = Buffer[buffout];
                buffout++;
                if(buffout >= BUFFLEN)
                        buffout=0;
                return(unch);
        }
        else
                return(0xff);
}

//以下为主函数
void main()
{
        unsigned char unChar;
        short bExit_Flag=0;

        OpenPort(); //打开串口

        fprintf(stdout, "\n\nReady to Receive DATA\n"
                        "press [ESC] to quit...\n\n");

        do {
                if (kbhit())
                {
                        unChar=getch();
                        /* Look for an ESC key */
                        switch (unChar)
                        {
                        case 0x1B:   //ESC的ASCII值为27
                                bExit_Flag = 1;  /* Exit program */
                                break;
                        //You may want to handle other keys here
                        }
                }
                unChar = read_char();  //从缓冲区中读数
                if (unChar != 0xff)
                {
                        fprintf(stdout,"%c",unChar);
                }
        } while (!bExit_Flag);

        ClosePort(); //关闭串口
}

作者: sratlf    时间: 2013-6-14 09:14
http://www.chenall.net/post/grub4dos_biosint/  不知道这个有没有帮助
作者: 不点    时间: 2013-6-14 10:48
本帖最后由 不点 于 2013-6-14 11:16 编辑

看了,三楼提供的代码非常好。

我感觉它可以转换成 grub4dos 的 32 位应用程序。

grub4dos 的 32 位应用程序,最适合用 C 语言来编写。而楼主提供的代码,正是 C 语言代码,因此,很自然地,它可以转换成 grub4dos 的 32 位应用程序。

代码中没有出现任何中断调用,对硬件底层的操作全都是通过嵌入的汇编指令 IN 和 OUT 来实现的。这样的代码,完全可以用 grub4dos 的 32 位应用程序来实现。

你可以参照 chenall 的 hotkey 命令的代码,比葫芦画瓢,生成你自己的程序。chenall 有很多外部命令,你都可以拿来参考。

hotkey.c 里面的注释,是最新的,它详细说明了如何在 Linux 下编译 hotkey.c。你就以 hotkey 为主要的参考,其它外部命令中的 C 语言代码,作为次要参考。

如果 chenall 有时间,说不定 chenall 也可以给你提供一些帮助的。

即使没有 chenall 的帮助,我想,你自己搞定它,应该也不难。

有什么困难,可以继续在这里提出,我估计很多人可以帮你。

------------------------------------

发现一个问题:下面这个函数,只有函数类型的定义,却没有见到函数体。

void interrupt far  asyncint(...);

因此,你的源代码是不完整的。

-------------------------------------

对不起,看到了 asyncint 的函数体了。

既然有接管中断的操作,那还是使用 16 位程序比较合适。

先说到这里吧,你先有个大致的印象。




作者: 不点    时间: 2013-6-14 22:03
用grub4dos肯定行,不过,你得稍稍学习一下才行。坦率地说,这年月,很多人都懒了,不愿意学习。要想让人家学新东西,必须先得给钱,给奖品才行,否则人家拒绝学习。

所以,我想到一个偷懒的办法。

你干脆在 dos 下做,不用学习新知识了。

dos 越来越不能启动了,但是,grub4dos通常是能启动的。你启动到grub4dos,有着启动成功率高的保证。然后,你map一个虚拟软盘,进入dos,这当然是百分之百成功的了。然后再运行你的com通信软件,这就行了。


作者: 2012goodbye    时间: 2013-6-14 23:11
我知道用grub4dos肯定行,我也知道我需要学习,所以我在网上找了很久,最后实在没有办法了才在这里求助。。。。

这一个懒我是偷不了的,我需要的就是通过grub4dos引导不同的dos系统镜像。

我的测试系统是一个x86兼容的嵌入式系统,通过不同的dos测试程序测试不同的环境。

现在的测试是当测试不同的产品是每次都需要重新做CF卡,更新程式。很麻烦!!

我现在想做的就是通过com口扫描来下载tftp服务器上不同的dos镜像,不必每次都重新更新程式...


作者: 2012goodbye    时间: 2013-6-14 23:15
感谢不点大师的建议!!!

不点大师能不能帮我提供点grub4dos更多的学习资料....

学习我是不怕的.....
作者: 不点    时间: 2013-6-14 23:57
这个是我的错,我开发了运行16  和32 位程序的功能,但给出的文档太简略。

16 位程序是首先在 wee 里面实现的,你读一读 wee 的readme就可以了。

32位程序也能做,但目前没有提供回调的机制,所以,你得自己处理中断描述符表。我看到你的com代码要接管中断号0C,在保护模式下,中断处理程序的地址需要记录在中断描述符表中,这就有点难了。如果你对于CPU很精通,你可能喜欢这么折腾,这样折腾的结果会是很漂亮很满意的,因为全部采用32位保护模式代码来实现,完全摆脱16 位的束缚。

你可以选择16位的方法,这相对容易一点。chenall把wee里面的代码移植到grub4dos中了,但wee的readme没有移植过来,所以你需要读wee的readme文件。
作者: 不点    时间: 2013-6-15 06:56
本帖最后由 不点 于 2013-6-15 07:00 编辑

16 位程序是模仿 dos 的 .COM 文件的格式来实现的。.COM 格式的优点是很简单,它其实是无格式的,比 .EXE 格式简单多了。

用汇编语言写这样的 16 位程序,比较好。你不可以调用 dos 的 API 来执行任何任务。比如说,你不可以调用 DOS 来执行打印字符的任务,你只能直接调用 bios 来执行打印字符的任务。

你可以在时空论坛寻找到很多开发资料,但很零散。比如说,grub4dos 的内存是如何使用的,用户程序可以使用哪些内存。

这些工作本来还可以继续完善的,但是,微软决定封杀 bios,所以,这个工作也就处于停顿状态了,你想啊,谁也不愿意去做无用功。

于是,这些工作就保持现状了,很难找到开发者继续完善这部分的功能。

再观望几年,如果 bios 真的被封杀死掉了,那么 grub4dos 也就死了。如果 bios 重新被拾起来,我想,到那时候,就有人继续完善这部分的功能了。

32 位的程序有着更大的灵活性,它访问内存更方便更自由。16 位的程序只能调用 bios,不能调用 grub4dos 的 api。32 位的程序可以调用 grub4dos 的 api。

中断描述符表位于物理地址 3M 处。

你可以用 cat --hex 来显示内存,了解默认的中断描述符是什么。

你可以修改相应于中断号 0C 的中断描述符,让它指向你的保护模式中断处理程序。


作者: 2012goodbye    时间: 2013-6-15 09:16
谢谢不点大师给的建议和提示!!!
我先去时空论坛去找找,看能不能再找我需要的资料。
grub4dos我也用了很久了,以前只是用了一点简单的功能,现在发现她其实有很多的好处都没被利用,或许是我的能力有限,亦或许是我的知识不够。
总之,希望更多的人了解她,让她的好处和方便为更多的去服务。




欢迎光临 无忧启动论坛 (http://bbs.wuyou.net/) Powered by Discuz! X3.3