OSD 設計
第一個任務是在Cortex M3上,實作一個程式,使其能夠控制攝影機,並且讓攝影機輸出對應的控制表單。
預期工作:
1.
設計 OSD 表單
2.
定義 OSD 表單對應的資料結構
3.
實作 OSD 控制邏輯
設計如下
1.
OSD表單:
假設OSD有三層表單,其表單結構如下:
l LEVEL-1
n LEVEL -11
u LEVEL -111
u LEVEL -112
n LEVEL -12
l LEVEL -2
n LEVEL -21
l LEVEL -3
n LEVEL -31
2.
定義資料結構
以C語言而言 “Level-1” 會分別對應到 ASCII 編碼的七個字元,但是OSD內部顯示 “Level-1” 字串時,並不一定是採用 ASCII編碼,就我拿到的版子而言,其OSD只支援64個字元。因此表單所顯示的字元編碼語ASCII不同,此部份需要轉換。
由於此表單只需要轉換一次,因此不需要將轉換的動作寫入在Cortex M5內,為了簡單起見,我直接使用JAVASript來實作一個簡單的轉換函數,產生需要使用的表格,當需要控制OSD時,直接使用轉換後的表格即可,程式碼如下:
<html>
<head>
<script type="text/javascript">
function Menu2Bytes()
{
var i, vLen, vTableSize, vIndex=0, vCh, bQuote;
var vpTempIn = "", vpTempOut = "" ;
var vpOutput="<p>The translation table (for C) is</p> "
var pLookUp = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!?(),.:;&;~*%+-X/=\"'_@"
var vpInput = document.getElementById("InputArea").value;
vTableSize = pLookUp.length;
vLen = vpInput.length;
bQuote = 0;
for(i=0;i<vLen;i++)
{
vCh = vpInput.charAt(i) ;
// Recored the menu string
vpTempIn += vCh;
// Generate the output string
vIndex = pLookUp.indexOf(vCh);
if(vIndex >= 0)
{
if(bQuote==0)
{
bQuote = 1;
vpTempOut = "{"
}
else
{
vpTempOut += ","
}
if(vIndex<10)
vpTempOut += "0x0" + vIndex;
else
vpTempOut += "0x" + vIndex;
}
else
{
vpOutput = vpOutput + vpTempOut + "}, //" + vpTempIn + "<p></P>"
bQuote = 0;
vpTempIn = ""
vpTempOut = ""
}
}
document.getElementById("demo").innerHTML=vpOutput;
}
</script>
</head>
<body>
<h1>Translate the menu to bytes for C language </h1>
<p>Paste the menu design here.</p>
<textarea id = "InputArea" rows=10 cols=50 >
LEVEL-1
LEVEL-11
LEVEL-111
LEVEL-112
LEVEL-12
LEVEL-2
LEVEL-21
LEVEL-3
LEVEL-31</textarea>
<p id="demo">This is a paragraph.</p>
<button type="demo" onclick="Menu2Bytes()">Translate Menu</button>
</body>
</html>
註: 可以透過此網址,線上練習JavaScript。
確定了要顯示的字串之後,需要定義一個資料結構,此資料結構需要有以下特性:
l 顯示字串
l 找到目前位於哪一階層
l 進入下一階層
l 回到上一階層
l 列出同階層內的所有表單項目
l 找到對應需要設定的函數
根據以上需求,我將資料結構定義如下:
typedef struct
{
char Level;
// Level 1, 2, 3
eOSDCmd Cmd; // up,
down, right, left, enter, menu
char *pCaption; //
menu item string
tpCmdHandler pCmdHandler; // function to send command to
device
}_tOSDCmdTable;
產生的表格如下,共有8個欄位
static _tOSDCmdTable
_gpxCodeTable[OSD_TABLE_SIZE] =
{
{ 1, _eLevel_1, STR_LEVEL_1, NULL },
{ 2, _eLevel_1, STR_LEVEL_11, NULL },
{ 3, _eLevel_1, STR_LEVEL_111, NULL },
{ 3, _eLevel_1, STR_LEVEL_111, NULL },
{ 1, _eLevel_2, STR_LEVEL_1, NULL },
{ 2, _eLevel_2, STR_LEVEL_1, NULL },
{ 1, _eLevel_3, STR_LEVEL_1, NULL },
{ 2, _eLevel_3, STR_LEVEL_1, NULL },
};
3. 實作 OSD 控制邏輯
對於OSD的控制,一般會有兩種做法。四個控制鍵或是六個控制鍵。
這裡我假設產品會使用六個控制鍵來控制OSD,分別是Up, Down, Right, Left, Menu, Enter,使用者可以利用這些鍵來執行OSD所提供的各項功能。
其操作方式如下:
l 初始化 menu
找出gpxCodeTable內屬於 Level 1 的所有項目,製造表單項目,並且將目前的表單選項設定為第一筆
for(i=0; i<Table_Size; i++)
{
if(gpxCodeTable[i].Level
== 1)
{
memcpy(pOutput, gpxCodeTable[i].pCaption, strlen(gpxCodeTable[i].pCaption));
pOutput += 28; // change to next
line
}
}
l 找到目前位於哪一階層
CurrentLevel = gpxCodeTable[i].Level;
l 進入下一階層 (即列舉出下一階層的所有表單)
for(i= CurrentLevel; i<Table_Size; i++)
{
if(
(gpxCodeTable[i].Level > CurrentLevel) &&
(gpxCodeTable[i].Cmd == gpxCodeTable[CurrentLevel].Cmd)
)
{
memcpy(pOutput, gpxCodeTable[i].pCaption, strlen(gpxCodeTable[i].pCaption));
pOutput += 28; // change to next
line
}
}
l 回到上一階層 (即列舉出上一階層的所有表單)
for(i= CurrentLevel; i>0; i--)
{
if(gpxCodeTable[i].Level
< CurrentLevel)
{
UpperLevel = i+1;
}
}
for(i= UpperLevel ; i<Table_Size; i++)
{
if(
(gpxCodeTable[i].Level > CurrentLevel) &&
(gpxCodeTable[i].Cmd == gpxCodeTable[CurrentLevel].Cmd)
)
{
memcpy(pOutput, gpxCodeTable[i].pCaption, strlen(gpxCodeTable[i].pCaption));
pOutput += 28; // change to next
line
}
}
l 列出同階層內的所有表單項目
for(i= 0 ; i<Table_Size; i++)
{
if(
(gpxCodeTable[i].Level == CurrentLevel) &&
(gpxCodeTable[i].Cmd == gpxCodeTable[CurrentLevel].Cmd)
)
{
memcpy(pOutput, gpxCodeTable[i].pCaption, strlen(gpxCodeTable[i].pCaption));
pOutput += 28; // change to next
line
}
}
l 找到對應需要設定的函數
pCBFunction = gpxCodeTable[i]. pCmdHandler;
上述設計便可以達到以下功能
l 顯示 OSD menu
l 利用 up, down, left, right瀏覽OSD menu
l 離開 OSD menu