rgb to yuv

 

void RGB2YUV(BYTE *in, BYTE *out, DWORD len)
{
        int r,g,b;
        int y, cb,cr;
        int i;
        int data;

        for(i=0; i<len; i=i+4)
        {
                r = *(in+2);
                g = *(in+1);
                b = *(in);

                y= (0.257*r + 0.504*g + 0.098*b + 16);
                cb = -0.148*r - 0.291*g + 0.439*b + 128;
                cr = 0.439*r - 0.368*g - 0.071*b + 128;
                if(y <16)
                {
                        y = 16;
                }
                else if(y>235)
                {
                        y = 235;
                }

                if(cb <16)
                {
                        cb = 16;
                }
                else if(cb>240)
                {
                        cb = 240;
                }

                if(cr <16)
                {
                        cr = 16;
                }
                else if(cr>240)
                {
                        cr = 240;
                }
                *(DWORD *)out = 0x7f000000 + ((DWORD)cr<<16) + ((DWORD)cb<<8) + (DWORD)y;

                in += 4;
                out += 4;
        }
}
 

Windows 98 源代码

/*
微软最高机密——Windows 98 源代码
项目:Chicago(tm)
项目发行日期:1998年夏天
*/


#include "win31.h"
#include "win95.h"
#include "evenmore.h"
#include "oldstuff.h"
#include "billrulz.h"
#define INSTALL = HARD

char make_prog_look_big[1600000]; /*使程序看起来很大*/

void main()
{
 while(!CRASHED) {  /*如果不崩溃*/
  display_copyright_message();  /*显示版权信息*/
  display_bill_rules_message();  /*显示比尔的规则的信息*/
  do_nothing_loop();        /*进行空循环*/
  if (first_time_installation) {  /*如果是第一次安装*/
   make_50_megabyte_swapfile();   /*创建50M的交换文件*/
   do_nothing_loop();        /*进行空循环*/
   totally_screw_up_HPFS_file_system(); /*将HPFS文件系统完全搞乱*/
   search_and_destroy_the_rest_of_OS/2(); /*搜寻并删除OS/2的所有残余信息*/
   hang_system();  /*挂起系统*/
   }
  write_something(anything); /*随便写一些信息*/
  display_copyright_message(); /*显示版权信息*/
  do_nothing_loop();  /*进行空循环*/
  do_some_stuff();
  if (still_not_crashed) {  /*如果还没崩溃*/
   display_copyright_message(); /*显示版权信息*/
   do_nothing_loop();    /*进行空循环*/
   basically_run_windows_3.1(); /*基本上运行Windows 3.1*/
   do_nothing_loop();  /*进行空循环*/
   do_nothing_loop();  /*进行空循环*/
   }
  }

 if (detect_cache()) /*如果检测到缓存*/
  disable_cache();  /*使缓存失效*/

 if (fast_cpu()) {  /*如果CPU很快*/
  set_wait_states(lots); /*设置等待状态*/
  set_mouse(speed, very_slow); /*设置鼠标(速度很慢)*/
  set_mouse(action, jumpy);  /*设置鼠标(动作跳跃)*/
  set_mouse(reaction, sometimes); /*设置鼠标(有时反应)*/
  }

/* printf("Welcome to Windows 3.11"); */
/* printf("Welcome to Windows 95"); */

 printf("Welcome to Windows 98"); /*输出“欢迎使用Windows 98”*/

 if (system_ok()) /*如果系统正常*/
  crash(to_dos_prompt); /*崩溃(到DOS提示符)*/
 else
  system_memory = open("a:\swp0001.swp", O_CREATE);
  /*否则打开a:\swp0001.swp作为系统内存*/

 while(something) {
  sleep(5);   /*睡眠5秒钟*/
  get_user_input(); /*接收用户输入*/
  sleep(5);   /*睡眠5秒钟*/
  act_on_user_input(); /*对用户输入起反应*/
  sleep(5);   /*睡眠5秒钟*/
  }

 create_general_protection_fault(); /*产生一般保护错误*/
 blue_screnn(); /*蓝屏*/
}

 

补充编译警告

在实际的工程中,往往会出现callback函数的参数类型,定义和实际使用的并不一致。要注意强制类型转换。

在某个 struct 定义中使用了 union,而此 union 中定义了两个结构,第一个结构包含5个 UINT8 类型的成员,第二个结构包含1个指针类型成员,1个 UINT16 类型成员,1个 UINT8 类型成员。工程中两个结构都会使用到,而编译器无法知道程序使用的是 union 中的哪一个成员,默认为第一个。由此产生类型不匹配的编译警告,这里有产生错误的隐患。

一些资源

http://digilander.libero.it/robang/rubrica/serial.htm  --  Serial Programming Guide for POSIX Operating Systems

http://www.embed.com.cn/bbs/index.asp  --  嵌入开发网

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html  --  ANSI C Yacc grammar

http://www.51eda.com/bbs/index.asp  --  中国EDA技术网

http://bbs.driverdevelop.com/columns.php?action=columns  --  驱动开发网

http://www.linuxpilot.net.cn/  --  Linux Pilot

http://www.linuxworld.com/  --  linux world

http://www.linuxjournal.com/  --  linux journal

http://www.salon.com/tech/special/opensource/  --  the free software story

http://www.gentoo.org/  --  gentoo linux

http://www.linuxfocus.org/  --  linux focus

http://www.debian.org/intl/zh/mailing_lists  --  Debian 中文计划邮件列表

http://www.debian.org/MailingLists/  --  debian Mailing Lists

http://www.sgi.com/tech/stl/  --  Standard Template Library Programmer's Guide

 

一些资源

方便自己经常看看。

http://home.lzu.edu.cn/cjj/  --  一个C/C++学习小站

http://www.qaforums.com/  --  sqaforums

http://www.testage.net/html/index.html  --  测试时代

http://www.soft.com/  --  software research

http://www.sqe.com/stareast/  --  software testing

http://student.zjzk.cn/course_ware/data_structure/web/main.htm  --  数据结构

http://blog.csdn.net/jinhao  --  C++

http://blog.csdn.net/gigix  --  透明

http://blog.csdn.net/kathywp  --  DirectX

http://fanqiang.chinaunix.net/  --  永远的UNIX

http://www.iu.hio.no/~mark/unix/unix_toc.html  --  The unix programming environment

http://www.chinalinuxpub.com/  --  linux php mysql

http://cvsbook.red-bean.com/cvsbook.html  --  Open Source Development with CVS, 3rd Edition

http://www.gnu.org/software/libc/manual/  --  The GNU C Library

http://www.menuetos.net/  --  Menuet OS
 

编译警告

一个项目,编译出近千条warning。

大部分大部分大部分是下面这四条导致的。

      1)局部变量定义后使用前没有初始化。
      2)函数体在调用处后,调用前没有声明。
      3)类型转换。
      4)比较运算符两边变量的类型不同。

 

计划啥?

有人问:“在做测试计划时,如何估计软件的缺陷数量?”
这实在是一个很二的问题。
做计划的时候干吗要去估计Bug有多少?
有人回帖说:“作测试计划的时候,是应该估计一下该软件的BUG数量,BUG集中点,以及修改该BUG的难度与时间,如果这些不估计,那编写测试用例的时候无法对某些重要模块作出着重测试”。
神了,做测试计划的时候都能估计出修改Bug的难度和时间了,也别计划了,赶紧解Bug去吧。

外部变量申明的一个错误

C++中的外部变量不是类型安全的变量。

File: sub.cpp 

// the string to print
char str[] = "Hello World!\n";

 File: main.cpp 

#include <iostream>

extern char *str; // the string to print

int main()
{
    std::cout<< str << std::endl;
    return (0);
}

 在这里,str被认为是一个指针,程序运行到那儿,读其地址前4位,而前4位是“Hell”,不是一个地址,所以出错。

关于文件格式的两个链接

文件格式大全:http://www.moon-soft.com/program/FORMAT/

标准MIDI文件格式:http://www.daxia.com/list_1702.shtml

MIPS处理器设计透视-080403

跳转指令:

  • 最小操作码字段是6位,跳转目标可以用26位来寻址,又因为指令是4字节对齐,最低两个有效位(least significant)不需要存储,所以地址空间是:228=256M。
  • 条件分支跳转只有一个带符号的16位PC相对偏移域,同样,跳转范围是218字节大小。

MIPS处理器设计透视-080402

为每条指令都分配MEM阶段(从数据缓存中读/写 内存变量)是为了保证同一时刻不会有两条指令都去访问数据缓存。

MIPS指令集的规定:

  • 所有指令都是32位的。—>条件转移限制在64KB(216)范围内。
                         —>装入任一32位值需两条连续指令。
                         —>跳转指令中的目标地址常数用26位编码(MIPS指令里,最小的操作码字段是6位)。
  • 指令操作必须符合流水线,必须在一个时钟周期内执行完。
  • 3操作数指令。
  • 32个寄存器。
  • 寄存器0($0)总是返回0。
  • 无条件标志的代码。 

编址及内存访问:

  • load/store必须对齐:字节在任何地址都可以被传送;半字必须按偶数字节对齐;字必须按4字节边界对齐。

信号量和同步互斥

进程的互斥与P、V操作

一、临界资源

什么是临界资源:任何时候只允许一个进程使用的资源为临界资源。

什么是临界区:访问临界资源的代码段为临界区。

例如:
代码段1 

a = count;
a--;
count = a;

代码段2  

b = count;
b++;
count = b;

为临界区,count为临界资源。

对临界资源的访问必须满足以下条件:
一次只能有一个进程进入,其他进程等待。
进入者必须在有限时间内退出。
等待者应该有机会进入。

二、信号量

信号量的结构模型:(S,Q)
在2.4.x内核中,信号量数据结构定义为(include/asm/semaphore.h): 

struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
#if WAITQUEUE_DEBUG
long __magic;
#endif
};


信号量操作:
1) 初始化
2) P操作
a) S--
b) if(S < 0) 在Q队列中睡眠
     else 进入
3) V操作
a) S++
b) if(S <= 0) 唤醒一睡眠进程(等待队列中有进程在睡眠)
     else 继续
P操作可以理解为申请资源,V操作可以理解为释放资源,在2.4.x内核semaphore结构中,count是资源计数,为正数或0时表示可用资源数,-1表示没有空闲资源且有等待进程,至于等待进程的数量并不关心,实现中依赖了sleepers,比较复杂,但好处是是up操作非常简单,只需汇编原子地将count加1,如果小于等于0表示有进程等待,调用__up_wakeup() --> __up(),否则返回。linux中的实现可以到arch/i386/kernel/semaphore.c中看到(2.4.x kernel),__down()和__up()。

信号量实现:
用ITRON的一个简单实现<An ITRON Implementation>做为例子。我粗略地看了一下代码,关于信号量(semaphore)的P/V操作,有计数器控制和等待队列。
SEMCB(semaphore control block)结构中有id,队列,计数器等成员。 

OS_AcquireSemaphoreTimeOut()
{ ...
        lock()
        semcb->semcnt-- // counter --
        if(semcb->semcnt < 0)
        {
                make_wait() // make current task in wait state
                queue_insert_tpri() // insert by priority to the semaphore's
                //wait queue,which is a circular queue
        }
        unlock()
        ...
}

OS_FreeSemaphore()
{ ...
        lock()
        if(semcp->semcnt < 0)
        {
                wait_release_ok()
                |
                -> wait_release() // release a task from wait state
        }
        semcb->semcnt++ // counter ++
        unlock()
        ...
}

注:V操作中S先加1再判断是否小于等于0和先判断是否小于0再加1是等价的。
注:在这个实现中,semcnt值不仅正负分别表示资源空闲或有进程等待,其绝对值也是有意义的,为负时值代表等待的进程数,为正或零时值代表空闲的资源数。

三、同步互斥模型

S=1


P(S)
临界区
V(S)



P(S)
临界区
V(S)


生产者消费者问题
(生产者计算生成数,消费者打印之。)

1个生产者1个消费者,缓冲buf为1
2个信号量实现模型:put = 1 get = 0


计算x
P(put)
buf = x
V(get)


P(get)
y = buf
V(put)
打印y


1个生产者2个消费者,缓冲buf为1(2个消费者一个打印奇数一个打印偶数)
3个信号量实现模型:put = 1 getj = 0 geto = 0

计算x
P(put)
buf = x
if(x为奇)
        V(getj)
else
        V(geto)


P(getj)
y = buf
V(put)
打印y


P(geto)
y = buf
V(put)
打印y

这个模型比较直观,但是用了3个信号量。在计算出x后判断其奇偶再"V"不同的信号量。
如果只使用2个信号量如何实现,生产者计算出x后直接"V"一个信号量,2个消费者取出后判断是否打印还是不于理会。
2个信号量实现模型:put = 1 get = 0


计算x
P(put)
buf = x
V(get)

P(get)
y = buf
if(y为奇)
{
        V(put)
        打印y
}
else
        V(get)

 C

P(get)
y = buf
if(y为偶)
{
        V(put)
        打印y
}
else
        V(get)


1个生产者1个消费者,缓冲buf为m
2个信号量实现模型:put = m get = 0


计算x
P(put)
buf[t] = x
t = (++t) % m
V(get)

 B 

P(get)
y = buf[k]
k = (++k) % m
V(put)
打印y


N个生产者M个消费者,缓冲buf为m
4个信号量实现模型:put = m get = 0 T = 1 K = 1


计算x
P(put)
P(T)
buf[t] = x
t = (++t) % m
V(T)
V(get)


P(get)
P(K)
y = buf[k]
k = (++k) % m
V(K)
V(put)
打印y

 
四、删除一个信号量

删除一个信号量,系统应该释放一些资源。如果无进程在等待此信号量,处理比较简单。
如果有进程在等待此信号量,如何处理这些进程,有人说kill,但我看到的一个实现是唤醒。
除进程之外,这个等待队列也需要释放,否则会造成内存泄露。
不仅是删除一个信号量,在系统中当删除某个资源时,会释放等待队列的所有task。

OS_DelFlag --|
OS_DelMessageBuffer --|--> call wait_delete(QUEUE *) --> OS_DelSemaphore --| 

while()
{wait_release();...} // release all tasks blocked on specified wait queue


五、由来

为什么敲打这么个东西。因为有个自主实现的基于ITRON的OS需要测试。在测试其信号量资源时我补充了一个测试用例,即当有进程在等待一个信号量时删除此信号量系统会有如何反应。基于此,先给测试人员做了presentation介绍信号量及同步互斥模型。然后粗略地看了看linux 2.4.x,ITRON和ucLinux三个系统的P/V操作和删除信号量的实现。因工作繁忙没有深入研究,简单整理一下用了两个小时边解bug边偷闲着输入完。然后steedhorse帮忙做了检查,经过了一个小时的讨论,改了一些错误,在此感谢。
有的问题我不是很清楚,希望看了后能提出来大家讨论。

Non-Preemptive Kernel

非抢占(Non-Preemptive)内核中如果任务不主动放弃,就不会被其他的高优先极任务抢掉对于CPU的控制。一个ISR可以使一个更高优先级的任务进入等待运行状态,但ISR总是返回被中断的任务。如图:

①低优先级任务(LPT)执行;
②低优先级任务被中断;
③执行中断服务例程,使高优先级任务(HPT)就绪;
④中断服务例程返回到被中断的低优先级任务;
⑤低优先级任务继续执行;
⑥低优先级任务放弃CPU;
⑦高优先级任务运行。
这个比较简单,而非抢占内核的其他优点也都好理解。可书上有这么一句话:非抢占内核的一个优点是中断等待时间通常比较低。什么是中断等待时间?
往后翻10页,书上又写:中断等待时间=中断被禁止的最长时间量+在ISR中开始执行第一个指令的时间
这个式子我看了大约五分钟。又翻回前面那句话反复默念。然后我决定认为自己理解了。一个任务在执行,收到一个中断,而这时中断有可能是被禁止的,一直到中断重新被打开,CPU保存现场环境到堆栈,跳转到ISR。所谓“中断被禁止的最长时间”的意思是从收到中断到开中断这一段时间。而保存CPU现场后才开始执行ISR,那么保存现场的这个时间是不是包含在中断等待时间内?从上面的式子看是的。
但是又来个式子:中断响应时间=中断等待时间+保存CPU状态的时间(非抢占内核)。

糊涂了,什么是“在ISR中开始执行第一个指令的时间”?
问题出在哪?出在ISR。开中断后,ISR即接管,保存现场的动作是ISR做的,中断等待时间就是从收到中断到ISR接管的时间,然后保存现场,然后开始执行用户代码,到这时是中断响应时间。对于抢占内核,保存完现场后要调用一个内核函数,通知内核一个ISR在处理并允许内核记录中断嵌套的情况,所以前面说,非抢占内核的一个优点是中断等待时间通常比较低。

非抢占内核最大的问题是响应时间。一个就绪的高优先级任务可能要等待不可预期的一段时间才能运行,所以实时内核多是抢占内核。如图是抢占内核的情况:

①低优先级任务执行;
②异步事件使任务中断;
③响应异步事件,运行中断服务例程,使高优先级任务就绪;
④中断服务例程返回到高优先级任务;
⑤高优先级任务执行,直到它被中断转向执行优先级更高的任务;
⑥高优先级任务结束,内核切换到低优先级任务;
⑦低优先级任务继续执行。 

深入理解Linux内核-080327

文件访问权限附加标记(用在可执行文件)。
suid(set user id):进程执行一个文件时通常保持进程拥有者的UID。如果设置了suid标志位,进程就获得了该文件拥有者的UID。
sguid(set group id):进程执行一个文件时保持进程组的GID。如果折纸了sgid标志位,进程就获得了该文件组的ID。
当进程创建一个文件时,文件拥有者的ID就是该进程的UID。其组ID既可以是进程创建者的GID,也可以是父目录的GID,取决于父目录sgid标志位的值。

深入理解Linux内核-080326

Unix的每个进程都有一个当前的工作目录,它属于进程执行上下文(execution context)。

不允许给目录创建hard link,这可能会把目录树变为环形图,从而不能定位文件。

只同一文件系统中的文件间可创建hard link。

MIPS处理器设计透视-080326

MIPS体系结构具有独立的指令缓存和数据缓存。CPU可同时获取指令和读写内存变量。

安装卫星天线时计算方位角和仰角

输入:本地经度,本地纬度,卫星经度。

输出:卫星天线的方位角,仰角。 

需要数学库的支持,可调整M_PI的精度。 

void do_calculate(float local_longititude, float local_latitude, float satellite_longititude, float * orientation, float * evaluation)
{
        float   temp1, temp2, ori, eva;

        local_longititude        = local_longititude/100.0/180.0*M_PI;
        local_latitude              = local_latitude/100.0/180.0*M_PI;
        satellite_longititude   = satellite_longititude/100.0/180.0*M_PI;

        ori = atan(tan(local_longititude - satellite_longititude)/sin(local_latitude))/M_PI*180 + 180.0;

        if (ori < 0)
                *orientation = (INT32)(ori * 100.0 + 360);
        else
                *orientation = (INT32)(ori * 100.0);

        temp1 = cos(local_latitude);
        temp2 = cos(local_longititude - satellite_longititude);

        eva = atan((temp1*temp2 - 0.15)/sqrt(1 - (temp1*temp1*temp2*temp2))); // 0.15127

        if (eva < 0)
                *evaluation = (INT32)((eva/M_PI*180 + 360) * 100.0);
        else
                *evaluation = (INT32)(eva/M_PI*180 * 100.0);
}
 

豆瓣验证

doubanclaim21efc1da816c3afe