chapter 02-01

基本資料模型的建立

此章節說明如何建立資料模型.


資料模型檔案要放在 mint_cm/mcm_build/mcm_data_profile.xml.


資料模型是用來描述設備有提供哪些參數可使用, 資料模型的架構是樹狀結構, 格式為 XML 類型.
使用類似 HTML 的 table 和 td 的組合模式將資料分成一個區塊一個區塊來描述.


下面使用範例說明如何建立, 假設目前有個網路設備需要這些參數來操作這台網路設備的功能 :
資料區塊 資料名稱 說明
DATA-1 (device) 樹狀結構的根節點, 紀錄設備的基本資料, 靜態單筆資料
descript 字串資料, 紀錄設備的相關描述
serial_number 字節流資料, 紀錄設備的序號
DATA-2 (system) 紀錄基本設定, 靜態單筆資料類型
date 字串資料, 紀錄日期
ip_addr 字串資料, 紀錄設備的 IP 位址
uptime 無號整數資料, 紀錄設備已開機多久
loadind 浮點數資料, 紀錄設備的負載狀況
DATA-3 (vap) 紀錄無線網路存取點設定, 動態多筆資料
ssid 字串資料, 紀錄無線介面的 SSID
channel 有號整數資料, 紀錄無線介面使用的頻道
DATA-4 (extra) 紀錄每個無線網路存取點的額外設定, 靜態單筆資料
hidden 有號整數資料, 紀錄是否隱藏無線介面
tx_power 有號整數資料, 紀錄無線介面的發射功率
DATA-5 (station) 紀錄每個無線網路存取點的站台設定, 動態多筆資料
mac_addr 字串資料, 紀錄站台的 MAC 位址
rule 關聯資料, 紀錄站台要使用哪條限制規則 (limit)
DATA-6 (limit) 紀錄站台相關限制設定, 動態多筆資料
name 字串資料, 紀錄規則的名稱
priority 有號整數資料, 紀錄站台的優先權
DATA-7 (client) 紀錄連線上的站台資料, 動態多筆資料
mac_addr 字串資料, 紀錄站台的 MAC 位址
location_x 浮點數資料, 紀錄站台所在的 X 座標
location_y 浮點數資料, 紀錄站台所在的 Y 座標

模型的架構會大致如下 :
<device>
  <descript></descript>
  <serial_number></serial_number>

  <system>
    <date></date>
    <ip_addr></ip_addr>
    <uptime></uptime>
    <loading></loading>
  </system>

  <vap>
    <ssid></ssid>
    <channel></channel>

    <extra>
      <hidden></hidden>
      <tx_power></tx_power>
    </extra>

    <station>
      <mac_addr></mac_addr>
      <rule></rule>
    </station>
  </vap>

  <limit>
    <name></name>
    <priority></priority>
  </limit>

  <client>
    <mac_addr></mac_addr>
    <locaion_x></locaion_x>
    <locaion_y></locaion_y>
  </client>
</device>



步驟一 : 加入 XML 開頭.
<?xml version="1.0"?>



步驟二 : 加入 base 資訊 (用來描述額外的資訊).
格式 :
<base version="$(version)">
</base>

實際 :
<?xml version="1.0"?>

<base version="1.0">
</base>



version=$(version)
表示此資料模型的版本, 格式可以隨意自訂, 如 [1] [1.2] [a.b] [2.1b] 都可.


步驟三 : 加入資料模型.
資料模型內容分成二大類, 群組(group)成員(member), 類似 HTML 的 table 和 td.
以 [DATA-01] 來說, [device] 就是 group, [descript] 就是 member.

先加入 group :
格式 :
<$(name) type="$(type)" max="$(max)" save="$(save)">
</$(name)>

實際 :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
</device>
</base>


資料模型必須放在 <base>...</base> 之內.

$(name)
表示資料的名稱, 限制 :
可使用的字元有 a ~ z, A ~ Z, 0 ~ 9, _
開頭字元必須是 a ~ z, A ~ Z, _
長度不可超過 254 (MCM_DTYPE_SNLEN_TD - 1)
同一層的 group 和 member 的名稱不可重複

type="$(type)"
表示 group 的類型 :
說明
gs [group-static]
表示此 group 只能容納靜態單筆資料, 能做 取得 / 設定 二種功能
gd [group-dynamic]
表示此 group 能夠容納動態多筆資料, 能做 取得 / 設定 / 增加 / 刪除 四種功能

max="$(max)"
表示 group 能夠容納的最大資料筆數 :
$(type) (MCM_DTYPE_USIZE_TD)
gs 1
gd 1 ~ 4294967295

save="$(save)"
表示 group 的資料是否要寫回檔案 :
說明
0 資料不寫回檔案
1 資料要寫回檔案

接著加入 member :
格式 :
<$(name) type="$(type)">$(default)</$(name)>

實際 :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>
</device>
</base>



$(name)
表示資料的名稱, 限制 :
[參考]

type="$(type)"
表示 member 的資料類型 :
說明
ek [entry-key] (MCM_DTYPE_EK_TD)
預留的資料, 紀錄此筆資料 key 值, 用來定位每筆資料
每個 group 都必須固定有一個此類型的 member
rk [related-key] (MCM_DTYPE_RK_TD)
需要關聯其他筆資料時, 需要記錄其 key 值, 但是 ek 類型只能有一個, 所以使用此種類型的資料來記錄
isc [integer-signed-char] (MCM_DTYPE_ISC_TD)
整數類型資料
iuc [integer-unsigned-char] (MCM_DTYPE_IUC_TD)
整數類型資料
iss [integer-signed-short] (MCM_DTYPE_ISS_TD)
整數類型資料
ius [integer-unsigned-short] (MCM_DTYPE_IUS_TD)
整數類型資料
isi [integer-signed-int] (MCM_DTYPE_ISI_TD)
整數類型資料
iui [integer-unsigned-int] (MCM_DTYPE_IUI_TD)
整數類型資料
isll [integer-signed-long-long] (MCM_DTYPE_ISLL_TD)
整數類型資料
iull [integer-unsigned-long-long] (MCM_DTYPE_IULL_TD)
整數類型資料
ff [float-float] (MCM_DTYPE_FF_TD)
浮點數類型資料
fd [float-double] (MCM_DTYPE_FD_TD)
浮點數類型資料
fld [float-long-doouble] (MCM_DTYPE_FLD_TD)
浮點數類型資料
s:$(size) [string] (MCM_DTYPE_S_TD)
字串類型資料
size 表示字串緩衝的大小, 範圍 2 ~ 4294967295 (MCM_DTYPE_USIZE_TD)
b:$(size) [bytes] (MCM_DTYPE_B_TD)
字節流類型資料
size 表示字節緩衝的大小, 範圍 1 ~ 4294967295 (MCM_DTYPE_USIZE_TD)

$(default)
用來紀錄 member 的初始值 :
$(type)
ek 不可為空, 0
rk 不可為空, 0 ~ 4294967295
isc 不可為空, -128 ~ 127
iuc 不可為空, 0 ~ 255
iss 不可為空, -32768 ~ 32767
ius 不可為空, 0 ~ 65535
isi 不可為空, -2147483648 ~ 2147483648
iui 不可為空, 0 ~ 4294967295
isll 不可為空, -9223372036854775808 ~ 9223372036854775807
iull 不可為空, 0 ~ 18446744073709551615
ff 不可為空
fd 不可為空
fld 不可為空
s:$(size) 可為空, 不為空須注意字串資料長度和緩衝大小

可以使用 Unicode 字元, 特定字元 (含 Unicode), 必須以特定格式輸入 :
% + $(ASCII-Code (雙位數 16 進制, 大小寫皆可))

可以列印的 ASCII 字元 (0x20 ~ 0x7E) 有二個字元列為特定字元 :
[ ](0x20) 改輸入 %20
[%](0x25) 改輸入 %25

不可列印的 ASCII 字元都是特定字元 :
[\t](0x09) 改輸入 %09
[\r](0x0A) 改輸入 %0A
[\n](0x0D) 改輸入 %0D
...

內部字串資料是以 UTF-8 格式儲存, 把 Unicode 轉 UTF-8 後用上述方式輸入, 例如 :
[資] 的 UTF-8 編碼為 E8 B3 87, 輸入 %E8%B3%87

UTF-8 編碼長度為 1 ~ 6, 需注意緩衝大小, 例如要儲存 100 個 Unicode 字元, 緩衝大小至少要 : (100 * 6) + 1 = 601
b:$(size) 可為空, 不為空須注意字節資料長度和緩衝大小

必須以特定格式輸入 :
$(Byte-Code (雙位數 16 進制, 大小寫皆可))

例如 :
0011A46DEE94

加入 [DATA-02] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>
</device>
</base>



加入 [DATA-03] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>

  <vap type="gd" max="16" save="1">
    <ekey type="ek">0</ekey>
    <ssid type="s:64"></ssid>
    <channel type="iui">0</channel>
  </vap>
</device>
</base>



加入 [DATA-04] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>

  <vap type="gd" max="16" save="1">
    <ekey type="ek">0</ekey>
    <ssid type="s:64"></ssid>
    <channel type="iui">0</channel>

    <extra type="gs" max="1" save="1">
      <ekey type="ek">0</ekey>
      <hidden type="isc">0</hidden>
      <tx_power type="iss">0</tx_power>
    </extra>
  </vap>
</device>
</base>



加入 [DATA-05] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>

  <vap type="gd" max="16" save="1">
    <ekey type="ek">0</ekey>
    <ssid type="s:64"></ssid>
    <channel type="iui">0</channel>

    <extra type="gs" max="1" save="1">
      <ekey type="ek">0</ekey>
      <hidden type="isc">0</hidden>
      <tx_power type="iss">0</tx_power>
    </extra>

    <station type="gd" max="32" save="1">
      <ekey type="ek">0</ekey>
      <mac_addr type="s:18">00:00:00:00:00:00</mac_addr>
      <rule type="rk">0</rule>
    </station>
  </vap>
</device>
</base>



加入 [DATA-06] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>

  <vap type="gd" max="16" save="1">
    <ekey type="ek">0</ekey>
    <ssid type="s:64"></ssid>
    <channel type="iui">0</channel>

    <extra type="gs" max="1" save="1">
      <ekey type="ek">0</ekey>
      <hidden type="isc">0</hidden>
      <tx_power type="iss">0</tx_power>
    </extra>

    <station type="gd" max="32" save="1">
      <ekey type="ek">0</ekey>
      <mac_addr type="s:18">00:00:00:00:00:00</mac_addr>
      <rule type="rk">0</rule>
    </station>
  </vap>

  <limit type="gd" max="64" save="1">
    <ekey type="ek">0</ekey>
    <name type="s:32"></name>
    <priority type="isi">-1</priority>
  </limit>
</device>
</base>



加入 [DATA-07] :
<?xml version="1.0"?>

<base version="1.0">
<device type="gs" max="1" save="1">
  <ekey type="ek">0</ekey>
  <descript type="s:256">Network-Device</descript>
  <serial_number type="b:10">0022E5A1CC9F</serial_number>

  <system type="gs" max="1" save="1">
    <ekey type="ek">0</ekey>
    <date type="s:12">2015/01/01</date>
    <ip_addr type="s:46">192.168.1.1</ip_addr>
    <uptime type="iull">0</uptime>
    <loading type="fd">0</loading>
  </system>

  <vap type="gd" max="16" save="1">
    <ekey type="ek">0</ekey>
    <ssid type="s:64"></ssid>
    <channel type="iui">0</channel>

    <extra type="gs" max="1" save="1">
      <ekey type="ek">0</ekey>
      <hidden type="isc">0</hidden>
      <tx_power type="iss">0</tx_power>
    </extra>

    <station type="gd" max="32" save="1">
      <ekey type="ek">0</ekey>
      <mac_addr type="s:18">00:00:00:00:00:00</mac_addr>
      <rule type="rk">0</rule>
    </station>
  </vap>

  <limit type="gd" max="64" save="1">
    <ekey type="ek">0</ekey>
    <name type="s:32"></name>
    <priority type="isi">-1</priority>
  </limit>

  <client type="gd" max="128" save="0">
    <ekey type="ek">0</ekey>
    <mac_addr type="s:18"></mac_addr>
    <location_x type="fld">0</location_x>
    <location_y type="fld">0</location_y>
  </client>
</device>
</base>



資料模型到此就建立完成.


註解的使用

註解符號是 <!---->

可以使用 單行, 多行, 巢狀 模式的註解.

<!-- 必須在文字最前面, --> 必須在文字最後面.

範例 :
<!-- text -->

<!--
text
-->

<!--
<!-- text -->
-->

<!--
<!--
text
-->
-->



注意事項

01.  樹根的 group 必須是 gs 類型.


02.  每個 group 都必須固定有一個 ek 類型的 member.


03.  沒有 child-group 的 group 必須要有 member (不含 ek 類型).
<GroupA>
  <GroupB>
    <GroupC>
      ...
    </GroupC>
  </GroupB>
</GroupA>


04.  若 group 的 $(save) 設為 0, 則內部的 child-group 的 $(save) 都必須是 0.
<GroupA type="gs" max="1" save="1">
  <GroupB1 type="gd" max="10" save="0">
    <GroupC1 type="gd" max="15" save="0">
      <GroupD1 type="gd" max="20" save="0">
      </GroupD1>
    </GroupC1>
  </GroupB1>
  <GroupB2 type="gs" max="1" save="1">
  </GroupB2>
</GroupA>


05.  group 類型的標籤必須是區塊模式 (頭尾標籤在不同行).
member 類型的標籤必須是單行模式 (頭尾標籤在同一行).
group :
<Group>
...
</Group>

member :
<Member>...</Member>


06.  檔案的最後必須多加一行換行.
<?xml version="1.0"?>
<base version="1.0">
  ...
</base>
-- 多一行 --


編譯資料模型

進入 mint_cm, 使用 make binary_profile 來編譯.

會自動使用 mint_cm/mcm_build/mcm_build 進行處理, 使用方法 :
mcm_build <-d> <-m> <-s> <-t>
參數 讀寫 說明
<-d data_profile_path> mcm_data_profile.xml
資料模型檔案
<-m model_profile_path> mcm_model_profile.txt
給程式讀取的資料模型檔案
<-s store_profile_path> mcm_store_profile.txt
給程式讀取的資料模型設定值檔案
<-t top_path> mint_cm 所在的路徑

編譯無誤完成後, 會產生幾個檔案 :
mint_cm/mcm_build
mcm_model_profile.txt 給程式讀取的資料模型檔案
mcm_store_profile.txt 給程式讀取的資料設定的預設值檔案
mcm_store_profile_default.txt 給程式讀取的資料設定的預設值檔案 (實際使用的)
mint_cm/mcm_daemon
mcm_data_ininfo_auto.h
mcm_data_info_auto.c
mint_cm/mcm_lib/mcm_lheader
mcm_data_exinfo_auto.h
mint_cm/mcm_lib/mcm_jslib
mcm_jslib_data_info_auto.js


資料模型錯誤資訊

編譯資料模型時, 會檢查是否有錯誤, 發現錯誤後會顯示錯誤訊息並停止編譯.

錯誤訊息格式 :
profile error, line $(error_line), code $(error_code) :
$(descript)

範例 :
mcm_build.c(0641):
profile error, line 13, code INVALID_NAME_05 :
invalid tag [name], name can not be duplication [<descript>...</descript>]
mcm_build.c(2059): call check_name_format2() fail
mcm_build.c(2285): call load_node_profile() fail
mcm_build.c(0398): call load_xml_profile() fail

$(error_line)
在第幾行發生錯誤.

$(error_code)
錯誤代號.

$(descript)
錯誤原因的簡單描述.

錯誤代號表 :
代號 說明
INVALID_TAG_01 此行的文字長度太短
INVALID_TAG_02 標籤的頭尾名稱必須相同, <uptime>...</uptime>
INVALID_TAG_SYMBOL_01 標籤 <...>...</...> 的 [<] [>] [<] [>] [/] 符號有缺少
INVALID_TAG_SYMBOL_02
INVALID_TAG_SYMBOL_03
INVALID_TAG_SYMBOL_04
INVALID_TAG_SYMBOL_05
INVALID_CLASS_01 最開始的標籤組必須是 <base>...</base>
INVALID_NAME_01 標簽名稱不可為空
INVALID_NAME_02 標簽名稱長度太長 [詳細]
INVALID_NAME_03 標簽名稱格式有錯誤 [詳細]
INVALID_NAME_04
INVALID_NAME_05 標簽名稱發生重複 [詳細]
INVALID_ATTRIBUTE_01 標籤的屬性缺少 [=] 符號, <uptime type="iui">...</uptime>
INVALID_ATTRIBUTE_02 標籤的屬性無效
<base></base> 類型可以使用的有 [version]
group 類型可以使用的有 [type] [max] [save]
member 類型可以使用的有 [type]
INVALID_ATTRIBUTE_03 標籤的屬性缺少 ["] 符號, <uptime type="iui">...</uptime>
INVALID_ATTRIBUTE_04
INVALID_ATTRIBUTE_05 標籤的屬性有缺少,
<base></base> 類型要有 [version]
group 類型要有 [type] [max] [save]
member 類型要有 [type]
INVALID_TYPE_01 此類型的標籤無法使用此屬性 [type]
INVALID_TYPE_02 標籤屬性 [type] 的值無效 [詳細-group] [詳細-member]
INVALID_TYPE_03
INVALID_TYPE_04 標籤屬性 [type] 的值為 [s:<size>] 時, 其緩衝大小的設定有誤, [詳細]
INVALID_MAX_01 此類型的標籤無法使用此屬性 [max]
INVALID_MAX_02 標籤屬性 [type] [max] [save] 必須照順序輸入
INVALID_MAX_03 此類型的標籤無法使用此屬性 [max]
INVALID_MAX_04 標籤屬性 [max] 的值無效 [詳細]
INVALID_MAX_05
INVALID_MAX_06
INVALID_SAVE_01 此類型的標籤無法使用此屬性 [save]
INVALID_SAVE_02 標籤屬性 [type] [max] [save] 必須照順序輸入
INVALID_SAVE_03 此類型的標籤無法使用此屬性 [save]
INVALID_SAVE_04 標籤屬性 [save] 的值無效 [詳細]
INVALID_SAVE_05
INVALID_SAVE_06 若 parent-group 的 [save]0, 則所有 child-group 的 $(save) 都必須是 0 [詳細]
INVALID_ARRANGE_01 標籤的排列方式錯誤 [詳細]
INVALID_ARRANGE_02
INVALID_DEFAULT_01 標籤的 $(default) 值無效 [詳細]
INVALID_DEFAULT-INTEGER_01 標籤的 $(default) 值無效 (整數類型) [詳細]
INVALID_DEFAULT-INTEGER_02
INVALID_DEFAULT-FLOAT_01 標籤的 $(default) 值無效 (浮點數類型) [詳細]
INVALID_DEFAULT-FLOAT_02
INVALID_DEFAULT-STRING_01 標籤的 $(default) 值無效 (字串類型) [詳細]
INVALID_DEFAULT-STRING_02
INVALID_DEFAULT-STRING_03
INVALID_DEFAULT-STRING_04
INVALID_DEFAULT-STRING_05
INVALID_DEFAULT-STRING_06
INVALID_DEFAULT-BYTES_01 標籤的 $(default) 值無效 (字節流類型) [詳細]
INVALID_DEFAULT-BYTES_02
INVALID_DEFAULT-BYTES_03
INVALID_NODE_01 根結點的 group 必須是 [gs] 類型 [詳細]
INVALID_NODE_02 member 必須放在 group 內, 不可單獨出現
INVALID_NODE_03 標籤的頭尾名稱必須相同 <uptime>...</uptime>
INVALID_NODE_04 每個 group 都必須固定有一個 [ek] 類型的 member [詳細]
INVALID_NODE_05 沒有 child-group 的 group 必須要有 member (不含 [ek] 類型) [詳細]


編譯指令的使用

編譯的操作是在 mint_cm 目錄, 可用的指令 :
指令 說明
binary_profile 處理資料模型
binary_library 編譯函式庫
binary_httpd 編譯網頁伺服器
binary_daemon 編譯執行檔
install_profile 複製資料模型和資料預設值檔到 mint_cm\run
install_library 複製相關的函式庫到 mint_cm\run
install_httpd 複製相關網頁伺服器設定檔和執行檔到 mint_cm\run
install_daemon 複製相關的執行檔到 mint_cm\run
all 依序編譯 binary_profile binary_library binary_httpd binary_daemon install_library install_httpd install_profile install_daemon
clean 清除編譯的結果
example_add KEY=$(key) 將指定的範例目錄內的檔案複製到對應的程式目錄, 之後做完整編譯 all
example_del KEY=$(key) 清除編譯結果 clean, 之後將 example_add 時複製過去的檔案刪除


範例程式的使用

01.  範例程式目錄在 mint_cm/usage/example/0201.


02.  下面關於 make 的操作都是在 mint_cm 目錄.


03.  第一次使用, 使用 make example_add KEY=0201 載入範例並編譯.


04.  有修改的話, 使用 make binary_profile 重新編譯.
資料模型錯誤的話, 會顯示錯誤訊息.
資料模型正確的話, 會產生對應的檔案.


05.  測試完畢不使用後, 使用 make example_del KEY=0201 將範例移除.


06.  範例程式目錄下的檔案在做完 make example_add 後會複製到真正使用的位置, 要修改做測試的話要改在複製後的.
來源 profile/mcm_data_profile_0201.xml
目地 mint_cm/mcm_build/mcm_data_profile.xml
資料模型範例
有修改要使用 make all 重新編譯