7 定时器API(harib21g)
到现在为止,计划今天要讲的关于窗口操作功能的部分已经全部完成了,不过现在时间还早,我们来做点好玩的吧。今天我们还没有写过新的API,那现在我们就来做个新的API吧,比如说,定时器的API。
记得在12.2节中我们实现了用定时器来计时的功能,当时我们高兴了半天,因为我们的操作系统可以用来泡面了。不过现在我们的操作系统又回到了派不上什么用场的状态,即便可以显示窗口、画点、画直线,但它却不能帮我们解决实际问题呀。
因此,接下来我们打算让应用程序也可以使用定时器,然后就可以去吃碗泡面了。大家先把想吃的泡面还有开水准备好,趁这段时间笔者先来写程序了哦!
■■■■■
这次要编写的API如下。
获取定时器(alloc)
EDX=16
EAX=定时器句柄(由操作系统返回)
设置定时器的发送数据(init)
EDX=17
EBX=定时器句柄
EAX=数据
定时器时间设定(set)
EDX=18
EBX=定时器句柄
EAX=时间
释放定时器(free)
EDX=19
EBX=定时器句柄
思路确定了,接下来就是写程序了。
本次的console.c节选
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
(中略)
} else if (edx == 15) {
for (;;) {
(中略)
if (i >= 256) { /*键盘数据(通过任务A)等*/ /*这里!*/
reg[7] = i - 256;
return 0;
}
}
} else if (edx == 16) { /*从此开始*/
reg[7] = (int) timer_alloc();
} else if (edx == 17) {
timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);
} else if (edx == 18) {
timer_settime((struct TIMER *) ebx, eax);
} else if (edx == 19) {
timer_free((struct TIMER *) ebx); /*到此结束*/
}
return 0;
}
edx的取值为16~19,这个很简单,应该不用讲了。哦对了,edx = 17的情况需要稍微说一下,这里数据的编号加上了256,是因为在向应用程序传递FIFO数据时,需要先减去256。
此外,api_getkey,也就是edx = 15的部分也稍微修改了一下。之前我们写的是if (256 <= I && I <= 511),而现在修改成了if(i>=256),就是说,512以上的值也可以通过api_getkey来获取了。之所以要这样改,是因为现在应用程序不仅需要接收键盘的数据,还需要接收应用程序所设置的定时器发生超时时所传递的数据。
■■■■■
下面我们来编写应用程序。
本次的a_nask.nas节选
_api_alloctimer: ; int api_alloctimer(void);
MOV EDX,16
INT 0x40
RET
_api_inittimer: ; void api_inittimer(int timer, int data);
PUSH EBX
MOV EDX,17
MOV EBX,[ESP+ 8] ; timer
MOV EAX,[ESP+12] ; data
INT 0x40
POP EBX
RET
_api_settimer: ; void api_settimer(int timer, int time);
PUSH EBX
MOV EDX,18
MOV EBX,[ESP+ 8] ; timer
MOV EAX,[ESP+12] ; time
INT 0x40
POP EBX
RET
_api_freetimer: ; void api_freetimer(int timer);
PUSH EBX
MOV EDX,19
MOV EBX,[ESP+ 8] ; timer
INT 0x40
POP EBX
RET
本次的noodle.c节选
#include <stdio.h>
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
int api_getkey(int mode);
int api_alloctimer(void);
void api_inittimer(int timer, int data);
void api_settimer(int timer, int time);
void api_end(void);
void HariMain(void)
{
char *buf, s[12];
int win, timer, sec = 0, min = 0, hou = 0;
api_initmalloc();
buf = api_malloc(150 * 50);
win = api_openwin(buf, 150, 50, -1, "noodle");
timer = api_alloctimer();
api_inittimer(timer, 128);
for (;;) {
sprintf(s, "%5d:%02d:%02d", hou, min, sec);
api_boxfilwin(win, 28, 27, 115, 41, 7 /*白色*/);
api_putstrwin(win, 28, 27, 0 /*黑色*/, 11, s);
api_settimer(timer, 100); /* 1秒*/
if (api_getkey(1) != 128) {
break;
}
sec++;
if (sec == 60) {
sec = 0;
min++;
if (min == 60) {
min = 0;
hou++;
}
}
}
api_end();
}
关于noodle.c这里稍微讲解一下,之前操作系统显示的是秒,而现在我们需要显示时、分、秒,这样一来时间看起来会更直观,我们就不需要用泡面的3分钟再乘以60换算成秒了。
当定时器超时时,会产生128这样一个值,这个值不是由键盘的编码所使用的,因此除了定时器,别的事件不可能产生这个值。如果产生的数据是128以外的值,那一定是用户按了回车键或者其他什么键,这时应用程序结束退出。
■■■■■
要开始运行了哦,开水准备好了吗?“make run”,先往泡面里面倒好开水,然后运行noodle.hrb。好,3分钟到了,可以吃喽!
可以吃喽
现在我们的操作系统又可以派上用场了,不错不错。