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节选

  1. int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
  2. {
  3. (中略)
  4. } else if (edx == 15) {
  5. for (;;) {
  6. (中略)
  7. if (i >= 256) { /*键盘数据(通过任务A)等*/ /*这里!*/
  8. reg[7] = i - 256;
  9. return 0;
  10. }
  11. }
  12. } else if (edx == 16) { /*从此开始*/
  13. reg[7] = (int) timer_alloc();
  14. } else if (edx == 17) {
  15. timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);
  16. } else if (edx == 18) {
  17. timer_settime((struct TIMER *) ebx, eax);
  18. } else if (edx == 19) {
  19. timer_free((struct TIMER *) ebx); /*到此结束*/
  20. }
  21. return 0;
  22. }

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节选

  1. _api_alloctimer: ; int api_alloctimer(void);
  2. MOV EDX,16
  3. INT 0x40
  4. RET
  5. _api_inittimer: ; void api_inittimer(int timer, int data);
  6. PUSH EBX
  7. MOV EDX,17
  8. MOV EBX,[ESP+ 8] ; timer
  9. MOV EAX,[ESP+12] ; data
  10. INT 0x40
  11. POP EBX
  12. RET
  13. _api_settimer: ; void api_settimer(int timer, int time);
  14. PUSH EBX
  15. MOV EDX,18
  16. MOV EBX,[ESP+ 8] ; timer
  17. MOV EAX,[ESP+12] ; time
  18. INT 0x40
  19. POP EBX
  20. RET
  21. _api_freetimer: ; void api_freetimer(int timer);
  22. PUSH EBX
  23. MOV EDX,19
  24. MOV EBX,[ESP+ 8] ; timer
  25. INT 0x40
  26. POP EBX
  27. RET

本次的noodle.c节选

  1. #include <stdio.h>
  2. int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
  3. void api_putstrwin(int win, int x, int y, int col, int len, char *str);
  4. void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
  5. void api_initmalloc(void);
  6. char *api_malloc(int size);
  7. int api_getkey(int mode);
  8. int api_alloctimer(void);
  9. void api_inittimer(int timer, int data);
  10. void api_settimer(int timer, int time);
  11. void api_end(void);
  12. void HariMain(void)
  13. {
  14. char *buf, s[12];
  15. int win, timer, sec = 0, min = 0, hou = 0;
  16. api_initmalloc();
  17. buf = api_malloc(150 * 50);
  18. win = api_openwin(buf, 150, 50, -1, "noodle");
  19. timer = api_alloctimer();
  20. api_inittimer(timer, 128);
  21. for (;;) {
  22. sprintf(s, "%5d:%02d:%02d", hou, min, sec);
  23. api_boxfilwin(win, 28, 27, 115, 41, 7 /*白色*/);
  24. api_putstrwin(win, 28, 27, 0 /*黑色*/, 11, s);
  25. api_settimer(timer, 100); /* 1秒*/
  26. if (api_getkey(1) != 128) {
  27. break;
  28. }
  29. sec++;
  30. if (sec == 60) {
  31. sec = 0;
  32. min++;
  33. if (min == 60) {
  34. min = 0;
  35. hou++;
  36. }
  37. }
  38. }
  39. api_end();
  40. }

关于noodle.c这里稍微讲解一下,之前操作系统显示的是秒,而现在我们需要显示时、分、秒,这样一来时间看起来会更直观,我们就不需要用泡面的3分钟再乘以60换算成秒了。

当定时器超时时,会产生128这样一个值,这个值不是由键盘的编码所使用的,因此除了定时器,别的事件不可能产生这个值。如果产生的数据是128以外的值,那一定是用户按了回车键或者其他什么键,这时应用程序结束退出。

■■■■■

要开始运行了哦,开水准备好了吗?“make run”,先往泡面里面倒好开水,然后运行noodle.hrb。好,3分钟到了,可以吃喽!

7 定时器API(harib21g) - 图1

可以吃喽

现在我们的操作系统又可以派上用场了,不错不错。