Tuesday, August 21, 2007

The mythical man-month

ch2

好菜都得多花些時間準備,為了能讓您享受到更美味、更可口的佳餚,請您務必耐心稍待。

——紐奧良,ANTOINE餐廳的點菜單



軟體專案進行不順利的原因或許很多,但絕大部分都是肇因於缺乏良好的時程規劃所致:
  1. 我們目前的時程預估技術還非常不成熟,糟的是,這些不成熟的技術背後都反映出一個假設,亦即,一切都會進行得很順利,但這實在是大錯特錯。
  2. 我們的預估技術誤把工作量和專案進度混為一談,這又隱含了另一個假設,以為人力和工時可以互換。
  3. 由於我們對自己所做的預估都無法篤定,所以專案經理通常缺乏Antoine餐廳廚師那種委婉的堅持。
  4. 時程進行缺乏監控,並把其他工程領域上被證明可行或慣用的技術套在軟體工程上進行改革。
  5. 當發現時程延誤的時候,自然而然的(也很典型的)反應就是增加人手,但這簡直就是火上加油,只會把情況弄得更糟。
過於樂觀 :
第一個錯誤假設就是一切都會進行得很順利,亦即,每項工作都將只會耗費掉它「理應」耗費的時間。

就單獨一件工作而言,如果假設一切都將順利進行,其結果會對時程造成何種影響就要看運氣。從機率分佈的角度來看,「完全不延期」也是有一定的機會,所以, 或許它真的能如計畫所預期地進行,但是,如果面對的是大型軟體開發專案,包含的是一大群工作,而且彼此環環相扣,那麼,一切都將進行得很順利的機率將是微 乎其微。

人月的迷思 :
第二個錯誤的想法,是來自於預估和排定時程所使用的人月,這正是一般用來衡量工作量的單位。成本確實會隨著人力與工時的乘積而變, 但工作的進度可不是如此,所以用人月來衡量工作規模的大小是危險的,也是一個容易遭到誤解的迷思,使用人月的前題必須是在人力和工時可以互換 的情況之下。

只有當工作可被切分,而且投入工作的人彼此不用溝通,人力和工時的互換才算成立,像割小麥或採收棉花就是這樣,但這對程式設計來說卻完全不適用。

當一份工作因具有連續性的限制而不可切分時,就算投入再多的人力,也不會對時程有所影響,生小孩就是需要九個月,你叫多少個媽一起生都一樣,軟體工程就是像這樣的工作,因為它必須除錯,而除錯就具有連續性的本質。

系統測試 :
在時程中,組件除錯(component debugging)和系統測試(system test)是受連續性限制影響最徹底的部分,甚至,需要耗費的時間是基於所遭遇到的錯誤數目以及錯誤的棘手程度,理論上,這個數目應該是零,但因為樂觀, 使我們預期的錯誤數目往往會比真正遭遇到的少,因此測試總是大大地延誤時程。

我要特別指出,沒有分配足夠的時間給系統測試,就會釀成大災難,這是因為等到交貨在即,發現時間不夠用的時候,時間卻已經快用光了,而在這之前,都沒有人會意識到時程有什麼不對勁,結果,在噩耗、落後竟然都沒有任何預警的情況下,把你的顧客和老闆嚇一大跳。

要有勇氣堅持自己的預估 :
請注意,程式設計師的遭遇跟廚師一樣,顧客的催促也許會左右工作的預定完成時間,但對工作的實際完成時間不會有什麼影響。一客煎蛋卷,答應兩分鐘做 好,而且看起來應該可以順利上桌,但是如果到了兩分鐘還沒有做好,那麼這位顧客只有兩種選擇──繼續等,或者吃生的。你的軟體顧客也是只有這兩種選擇。   

當然廚師還有另外一種選擇,他可以把火加大,那煎蛋卷就完蛋了──有一半燒焦,另一半還是生的。   

我不認為軟體 專案經理在先天上就缺乏廚師的勇氣與堅持,或是在這點上比其他工程領域的管理者還差,但是在軟體界,以錯誤的時程去配合顧客期望的日期,這是比其他工程領 域還普遍的現象。對於缺乏數據、僅憑很少的資料、主要靠著專案經理的直覺所預估出來的時程,很難提出一個強而有力、能夠自圓其說,並足以擔保一切風險的辯 解。

明顯地,這必須從兩方面來解決。我們先要蒐集並告知大家有關生產力的資料、錯誤發生率的資料、預估時程的法則等等,唯有藉著分享這些資料,整個軟體界才能夠獲利。

另一方面,在為預估方法找到一個更為堅實的基礎之前,專案經理個人必須挺起胸膛,勇敢為自己的估計堅持立場,保證就算是他的直覺再不濟,也比用願望來做預估要好。   

雖然不夠嚴謹,看來也異於常理,我們還是在此提出Brooks定律:在一個時程已經落後的軟體專案中增加人手,只會讓它更加落後。(Adding manpower to a late software project makes it later.)   

這 定律破除了人月神話。軟體專案會耗費多少時間是看它有多少連續性的限制,該投入多少人力是看它可以切分成多少獨立的子工作,根據這兩點,我們就可以推論出 用人較少、耗時較多的時程(唯一的風險就是軟體落伍的問題),然而,你是無法得到一個用人較多、耗時較少而又行得通的時程。軟體專案進行不順利的原因或許 很多,但絕大部分都是缺乏良好的時程規劃所致。

博客來 人月神話 : 軟體專案管理之道

Friday, August 17, 2007

RF and Baseband of BT

RF(無線電):

  • 採用2.4GHz的ISM公用頻段 - 頻段從2400MHz 到 2483,5MHz,劃分為79個頻道,每個頻道1MHz (f=2402+k MHz, k=0,…,78)
  • 採用跳頻式展頻技術(Frequency Hopping Spread spectrum)- 每秒跳動1600次(在正常操作的情況下)1Mhz的頻道間距
  • 採用GFSK(Gaussian Frequency Shift Key)調變 - 數位FM模式,容許的峰值頻率偏差為175kHz
  • 最低功率的傳輸距離為10公尺,加大功率最多可達100公尺
Baseband(基頻):
  • BT device address: 每個bt device有一個48 bits的IEEE MAC, it's like an unique id of the device. MAC分成 -- Lower address(24 bits), Upper address(8 bits) and Non-significant address(16 bits)


  • BT clock: Every Bluetooth device shall have a native clock that shall be derived from a free running system clock. The clock determines critical periods and triggers the events in the device. Four periods are important in the Bluetooth system: 312.5 μs, 625 μs, 1.25 ms, and 1.28 s.
  • Piconet and Scatternet: a) single-slave piconet, b) multi-slave piconet and c) scatternet (master is also slave, many piconets form a scatternet)

  • 封包結構: access code, header, payload (this is the standard basic rate packet format)
  • Logical transport:
    • Synchronous Connection-Oriented (SCO) logical transport
    • Extended Synchronous Connection-Oriented (eSCO) logical transport
    • Asynchronous Connection-Oriented (ACL) logical transport
    • Active Slave Broadcast (ASB) logical transport
    • Parked Slave Broadcast (PSB) logical transport
SCO : Circuit-switched - 較適合語音(Voice)服務的傳輸方式,它有點像是在溝通的兩方之間設立一條專 用道路,這條專用道路在通話過程中不會有別人來Share。
ACL : Packet-switched - 大家共享一條高速公路,人少的時候,你可以開快一 點。塞車的時候,就會慢一點,通常較適合資料(Data)的傳輸。

Thursday, August 16, 2007

Bluetooth

Mapping between Bluetooth, OSI model and IEEE802 standards




Bluetooth Core System Architecture (the four lowest layer)



C-plane :

  • device control services that modify the behavior and modes of a Bluetooth device,
  • transport control services that create, modify and release traffic bearers (channels and links)
U-plane :
  • data services that are used to submit data for transmission over traffic bearers

Bluetooth controller operates the lowest three layers (Radio, Baseband and Link Manager layers) and the L2CAP layer is contained with the rest of the Bluetooth application in a host system.
The standard interface is called the Host to Controller Interface (HCI) and its service access points are represented by the ellipses on the upper edge of the Bluetooth controller subsystem.

Channel manager : responsible for creating, managing and destroying L2CAP channels for the transport of service protocols and application data streams.

L2CAP resource manager : responsible for managing the ordering of submission of PDU fragments to the baseband and some relative scheduling between channels to ensure that L2CAP channels with QoS commitments are not denied access to the physical channel due to Bluetooth controller resource exhaustion.

Device manager : responsible for all operation of the Bluetooth system that is not directly related to data transport, such as inquiring for the presence of other nearby Bluetooth devices, connecting to other Bluetooth devices, or making the local Bluetooth device discoverable or connectible by other devices.

Link manager : responsible for the creation, modification and release of logical links.

Baseband resource manager : responsible for all access to the radio medium. It has two main functions. At its heart is a scheduler that grants time on the physical channels to all of the entities that have negotiated an access contract. The other main function is to negotiate access contracts with these entities. An access contract is effectively a commitment to deliver a certain
QoS that is required in order to provide a user application with an expected performance.

Link controller : responsible for the encoding and decoding of Bluetooth packets from the data payload and parameters related to the physical channel, logical transport and logical link.

RF : responsible for transmitting and receiving packets of information on the physical channel.

Wednesday, August 1, 2007

在CE下自動開啟目錄

沒想到msdn library有CreateDirectory, RemoveDirectory
但就是沒有OpenDirectory
還好達哥之前有寫過
不然這個方法我大概要找很久吧 orz

void OpenFolder()
{
HWND hwnd;
SHELLEXECUTEINFO si;

memset (&si, 0, sizeof (si));
si.cbSize = sizeof (si);
si.fMask = 0;
si.hwnd = hwnd;
si.lpFile = TEXT ("\\My Flash Disk\\PEtestfolder"); //要開啟的資料夾
si.lpVerb = TEXT ("explore"); //特定參數

ShellExecuteEx (&si);
}

lpVerb
Long pointer to a string specifying the name of a verb. The verb specifies an action for the application to perform. The set of available verbs depends on the particular file or folder. It includes the commands listed in the context menu and the registry. The following table shows verbs that are usually valid.
Value Description
Edit The function opens an editor.
Find The function initiates a search starting from the specified directory.
Open The function opens the file specified by the lpFile parameter. The file can be an executable file or a document file. It can also be a folder. This is the default verb if no verb is specified.
Print The function prints the document file specified by lpFile.

其他的verbs要參考registry的HKEY_CLASSES_ROOT\object_name\Shell\verb

不懂的是explore這個參數是哪來的,如果設Open會不會有一樣的結果?
試了之後發現
也是可以的!

Friday, July 20, 2007

Loading Stream driver from ap

如果不想要系統啟動時由DeviceManager自動載入我們寫的driver,而是經由上層ap呼叫去load的話,則在platform.reg有一個地方要改 : 就是把[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Cin]的BuiltIn拿掉,系統就不會自動載入了,路徑可自定,不要在BuiltIn底下即可。
e.g. [HKEY_LOCAL_MACHINE\Drivers\Cin]


//cintest.cpp - demo ap to load driver
//---------------------------------------------------------------------------------
HANDLE hDevice; //handle to initialize the driver
HANDLE hSerial; //handle to open the driver, used by write, read, seek and ioctrl

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
DWORD cBytes_out, cBytes_in;

char cBuffer_out[] = "\f\n Hello WORLD! \n\r";
TCHAR cBuffer_in[80];

printf("\n CinTest Demo driver \n");

//使用ActivateDeviceEx時,lpszDevKey 路徑不用加上 HKEY_LOCAL_MACHINE,加的話driver叫不起來
hDevice = ActivateDeviceEx(L"Drivers\\Cin", NULL, 0, 0);
if (hDevice == INVALID_HANDLE_VALUE) { printf("file init errors \n", "%X", hDevice); return 0; }

hSerial = CreateFile(_T("CIN1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

if (hSerial == INVALID_HANDLE_VALUE) { printf("file open errors \n", "%X", hSerial); Sleep(4000); return 0; }

if (!WriteFile(hSerial, cBuffer_out, strlen(cBuffer_out), &cBytes_out, NULL))
{ printf("file write errors\n"); Sleep(4000); return 0; }
cBuffer_in[0] = 0;


if (ReadFile(hSerial, cBuffer_in, 1, &cBytes_in, NULL))
{
if (!WriteFile(hSerial, cBuffer_in, cBytes_in, &cBytes_out, NULL))
{ printf("\rfile write errors\n"); Sleep(4000); return 0; }
}

CloseHandle(hSerial);
DeactivateDevice(hDevice);
return 0;
}

Result :