[101] | 1 | /*
|
---|
| 2 | * TOPPERS ECHONET Lite Communication Middleware
|
---|
| 3 | *
|
---|
| 4 | * Copyright (C) 2015 Cores Co., Ltd. Japan
|
---|
| 5 | *
|
---|
| 6 | * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
|
---|
| 7 | * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
|
---|
| 8 | * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
|
---|
| 9 | * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
|
---|
| 10 | * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
|
---|
| 11 | * スコード中に含まれていること.
|
---|
| 12 | * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
|
---|
| 13 | * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
|
---|
| 14 | * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
|
---|
| 15 | * の無保証規定を掲載すること.
|
---|
| 16 | * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
|
---|
| 17 | * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
|
---|
| 18 | * と.
|
---|
| 19 | * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
|
---|
| 20 | * 作権表示,この利用条件および下記の無保証規定を掲載すること.
|
---|
| 21 | * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
|
---|
| 22 | * 報告すること.
|
---|
| 23 | * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
|
---|
| 24 | * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
|
---|
| 25 | * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
|
---|
| 26 | * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
|
---|
| 27 | * 免責すること.
|
---|
| 28 | *
|
---|
| 29 | * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
|
---|
| 30 | * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
|
---|
| 31 | * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
|
---|
| 32 | * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
|
---|
| 33 | * の責任を負わない.
|
---|
| 34 | *
|
---|
| 35 | * @(#) $Id: DeviceController.cs 108 2015-06-11 09:15:46Z coas-nagasima $
|
---|
| 36 | */
|
---|
| 37 |
|
---|
| 38 | using System;
|
---|
| 39 | using System.Collections.Generic;
|
---|
| 40 | using System.Diagnostics;
|
---|
| 41 | using System.Linq;
|
---|
| 42 | using System.Text;
|
---|
| 43 | using System.Text.RegularExpressions;
|
---|
| 44 | using System.Threading.Tasks;
|
---|
| 45 | using System.Xml;
|
---|
| 46 | using control;
|
---|
| 47 |
|
---|
| 48 | namespace ctrlui
|
---|
| 49 | {
|
---|
| 50 | public enum PropertyInputMode
|
---|
| 51 | {
|
---|
| 52 | Unknown,
|
---|
| 53 | Select,
|
---|
| 54 | Range,
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | public class PropertyInputInfo
|
---|
| 58 | {
|
---|
| 59 | public PropertyInputMode Mode;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | public class PropertySelectInput : PropertyInputInfo
|
---|
| 63 | {
|
---|
| 64 | public Dictionary<long, string> Option = new Dictionary<long, string>();
|
---|
| 65 |
|
---|
| 66 | public PropertySelectInput()
|
---|
| 67 | {
|
---|
| 68 | Mode = PropertyInputMode.Select;
|
---|
| 69 | }
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | public class PropertyRangeInput : PropertyInputInfo
|
---|
| 73 | {
|
---|
| 74 | public int Maximum;
|
---|
| 75 | public int Minimum;
|
---|
| 76 | public string MinDescrption;
|
---|
| 77 | public string MaxDescrption;
|
---|
| 78 |
|
---|
| 79 | public PropertyRangeInput()
|
---|
| 80 | {
|
---|
| 81 | Mode = PropertyInputMode.Range;
|
---|
| 82 | }
|
---|
| 83 | }
|
---|
| 84 |
|
---|
| 85 | public class DeviceController : UIDeviceController
|
---|
| 86 | {
|
---|
| 87 |
|
---|
| 88 | public class NodeInfo
|
---|
| 89 | {
|
---|
| 90 | private ENOD_ID m_NodeId;
|
---|
| 91 | private DeviceInfo m_Profile;
|
---|
| 92 | private List<DeviceInfo> m_Devices = new List<DeviceInfo>();
|
---|
| 93 |
|
---|
| 94 | public NodeInfo(ENOD_ID nodeId, DeviceInfo profile)
|
---|
| 95 | {
|
---|
| 96 | m_NodeId = nodeId;
|
---|
| 97 | m_Profile = profile;
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 | public ENOD_ID NodeId { get { return m_NodeId; } }
|
---|
| 101 |
|
---|
| 102 | public DeviceInfo Profile { get { return m_Profile; } }
|
---|
| 103 |
|
---|
| 104 | public List<DeviceInfo> Devices { get { return m_Devices; } }
|
---|
| 105 |
|
---|
| 106 | public object Data { get; set; }
|
---|
| 107 |
|
---|
| 108 | }
|
---|
| 109 | public class DeviceInfo : UIDeviceInfo
|
---|
| 110 | {
|
---|
| 111 | private JsonClassInfo m_ClassInfo;
|
---|
| 112 | private bool m_Profile;
|
---|
| 113 | private byte m_ClassGroupCode;
|
---|
| 114 | private byte m_ClassCode;
|
---|
| 115 | private byte m_InstanceCode;
|
---|
| 116 | private List<DevicePropertyInfo> m_Properties = new List<DevicePropertyInfo>();
|
---|
| 117 | private int m_EObjId;
|
---|
| 118 |
|
---|
| 119 | public DeviceInfo(JsonClassInfo eci, bool profile, byte x1, byte x2, byte x3, int eobjid)
|
---|
| 120 | {
|
---|
| 121 | m_ClassInfo = eci;
|
---|
| 122 | m_Profile = profile;
|
---|
| 123 | m_ClassGroupCode = x1;
|
---|
| 124 | m_ClassCode = x2;
|
---|
| 125 | m_InstanceCode = x3;
|
---|
| 126 | m_EObjId = eobjid;
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | public DeviceInfo(JsonClassInfo eci, WebApiObjectInfo dev)
|
---|
| 130 | : this(eci, dev.profile, dev.x1, dev.x2, dev.x3, dev.eobjid)
|
---|
| 131 | {
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | public DeviceInfo(JsonClassInfo eci, DevicePropertyInfo[] prps)
|
---|
| 135 | {
|
---|
| 136 | m_ClassInfo = eci;
|
---|
| 137 | m_Properties.AddRange(prps);
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | public JsonClassInfo ClassInfo { get { return m_ClassInfo; } }
|
---|
| 141 |
|
---|
| 142 | public bool Profile { get { return m_Profile; } }
|
---|
| 143 |
|
---|
| 144 | public byte ClassGroupCode { get { return m_ClassGroupCode; } }
|
---|
| 145 |
|
---|
| 146 | public byte ClassCode { get { return m_ClassCode; } }
|
---|
| 147 |
|
---|
| 148 | public byte InstanceCode { get { return m_InstanceCode; } }
|
---|
| 149 |
|
---|
| 150 | public List<DevicePropertyInfo> Properties { get { return m_Properties; } }
|
---|
| 151 |
|
---|
| 152 | public int EObjId { get { return m_EObjId; } }
|
---|
| 153 |
|
---|
| 154 | public object Data { get; set; }
|
---|
| 155 |
|
---|
| 156 | public string GetText()
|
---|
| 157 | {
|
---|
| 158 | if (m_ClassInfo != null)
|
---|
| 159 | return m_ClassInfo.description;
|
---|
| 160 | else
|
---|
| 161 | return String.Format("{0:X2}{1:X2}{2:X2}", m_ClassGroupCode, m_ClassCode, m_InstanceCode);
|
---|
| 162 | }
|
---|
| 163 | /// <summary>
|
---|
| 164 | /// プロパティ値を採用
|
---|
| 165 | /// </summary>
|
---|
| 166 | /// <param name="epc">番号</param>
|
---|
| 167 | /// <param name="edt">入力値</param>
|
---|
| 168 | internal void SetPropertyData(byte epc, byte[] edt)
|
---|
| 169 | {
|
---|
| 170 | DevicePropertyInfo dpi = m_Properties.FirstOrDefault(p => p.PropertyCode == epc);
|
---|
| 171 | if (dpi == null)
|
---|
| 172 | return;
|
---|
| 173 |
|
---|
| 174 | dpi.SetPropertyData(edt);
|
---|
| 175 | }
|
---|
| 176 | internal void AdoptInputData(byte epc)
|
---|
| 177 | {
|
---|
| 178 | DevicePropertyInfo dpi = m_Properties.FirstOrDefault(p => p.PropertyCode == epc);
|
---|
| 179 | if (dpi == null)
|
---|
| 180 | return;
|
---|
| 181 |
|
---|
| 182 | dpi.AdoptInputData();
|
---|
| 183 | }
|
---|
| 184 | public string GetObjectID()
|
---|
| 185 | {
|
---|
| 186 | string text = ClassGroupCode.ToString("X2")
|
---|
| 187 | + ClassCode.ToString("X2")
|
---|
| 188 | + InstanceCode.ToString("X2");
|
---|
| 189 | return text;
|
---|
| 190 | }
|
---|
| 191 | public void SetUIDevice(CtrlUI page)
|
---|
| 192 | {
|
---|
| 193 | base.UIDeviceSet(this, page);
|
---|
| 194 | }
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | public delegate void GetClassInfoCallback(JsonClassInfo eclass);
|
---|
| 198 | public delegate void GetClassInfoHandler(byte x1, byte x2, GetClassInfoCallback cb);
|
---|
| 199 | public delegate void CreateCallback(DeviceController dc);
|
---|
| 200 |
|
---|
| 201 | public class DevicePropertyInfo : UIDevicePropertyInfo
|
---|
| 202 | {
|
---|
| 203 | private JsonPropertyInfo m_PropertyInfo;
|
---|
| 204 | private byte m_PropertyCode;
|
---|
| 205 | private EPC_FLAG m_Flag;
|
---|
| 206 | private byte m_Size;
|
---|
| 207 | private byte[] m_Data;
|
---|
| 208 | List<PropertyInputInfo> m_InputTypes;
|
---|
| 209 | /// <summary>
|
---|
| 210 | /// コンストラクタ
|
---|
| 211 | /// </summary>
|
---|
| 212 | /// <param name="epi"></param>
|
---|
| 213 | /// <param name="epc"></param>
|
---|
| 214 | /// <param name="flag"></param>
|
---|
| 215 | /// <param name="size"></param>
|
---|
| 216 | public DevicePropertyInfo(JsonPropertyInfo epi, byte epc, EPC_FLAG flag, byte size)
|
---|
| 217 | {
|
---|
| 218 | m_PropertyInfo = epi;
|
---|
| 219 | m_PropertyCode = epc;
|
---|
| 220 | m_Flag = flag;
|
---|
| 221 | m_Size = size;
|
---|
| 222 | //base.SetProperty(this);
|
---|
| 223 | }
|
---|
| 224 | /// <summary>
|
---|
| 225 | /// コンストラクタ
|
---|
| 226 | /// </summary>
|
---|
| 227 | /// <param name="epi"></param>
|
---|
| 228 | /// <param name="prop"></param>
|
---|
| 229 | public DevicePropertyInfo(JsonPropertyInfo epi, WebApiPropertyInfo prop)
|
---|
| 230 | : this(epi, prop.epc, prop.flag, (byte)epi.size)
|
---|
| 231 | {
|
---|
| 232 |
|
---|
| 233 | }
|
---|
| 234 | public JsonPropertyInfo PropertyInfo
|
---|
| 235 | {
|
---|
| 236 | get { return m_PropertyInfo; }
|
---|
| 237 | }
|
---|
| 238 | public byte PropertyCode
|
---|
| 239 | {
|
---|
| 240 | get { return m_PropertyCode; }
|
---|
| 241 | }
|
---|
| 242 | public string GetPropertyCode(string format)
|
---|
| 243 | {
|
---|
| 244 | return PropertyCode.ToString(format);
|
---|
| 245 | }
|
---|
| 246 | /// <summary>
|
---|
| 247 | /// 可変長データ
|
---|
| 248 | /// </summary>
|
---|
| 249 | /// <returns>true:可変長データ</returns>
|
---|
| 250 | public bool IsValiable()
|
---|
| 251 | {
|
---|
| 252 | return (PropertyInfo == null) ? true : PropertyInfo.access.Contains("VARIABLE");
|
---|
| 253 | }
|
---|
| 254 | /// <summary>
|
---|
| 255 | /// アクセスルール
|
---|
| 256 | /// </summary>
|
---|
| 257 | public EPC_FLAG Flag
|
---|
| 258 | {
|
---|
| 259 | get { return m_Flag; }
|
---|
| 260 | }
|
---|
| 261 | public byte Size
|
---|
| 262 | {
|
---|
| 263 | get { return m_Size; }
|
---|
| 264 | }
|
---|
| 265 | /// <summary>
|
---|
| 266 | /// 表示名称を返します
|
---|
| 267 | /// </summary>
|
---|
| 268 | /// <returns></returns>
|
---|
| 269 | public string GetText()
|
---|
| 270 | {
|
---|
| 271 | if (m_PropertyInfo != null)
|
---|
| 272 | return m_PropertyInfo.description;
|
---|
| 273 | else
|
---|
| 274 | return String.Format("{0:X2}", m_PropertyCode);
|
---|
| 275 | }
|
---|
| 276 | /// <summary>
|
---|
| 277 | /// 入力値
|
---|
| 278 | /// </summary>
|
---|
| 279 | public byte[] InputData { get; set; }
|
---|
| 280 | /// <summary>
|
---|
| 281 | /// プロパティのデータ
|
---|
| 282 | /// </summary>
|
---|
| 283 | public byte[] Data { get { return m_Data; } }
|
---|
| 284 | /// <summary>
|
---|
| 285 | /// 書き込み待ち状態
|
---|
| 286 | /// </summary>
|
---|
| 287 | public bool IsWaitRes { get; set; }
|
---|
| 288 | public List<PropertyInputInfo> InputTypes { get { return m_InputTypes; } }
|
---|
| 289 | /// <summary>
|
---|
| 290 | /// プロパティ値を採用したとき、値をDataに入れる。
|
---|
| 291 | /// </summary>
|
---|
| 292 | /// <param name="edt"></param>
|
---|
| 293 | public void SetPropertyData(byte[] edt)
|
---|
| 294 | {
|
---|
| 295 | m_Data = edt;
|
---|
| 296 | }
|
---|
| 297 | public void AdoptInputData()
|
---|
| 298 | {
|
---|
| 299 | m_Data = InputData;
|
---|
| 300 | InputData = null;
|
---|
| 301 | }
|
---|
| 302 | /// <summary>
|
---|
| 303 | /// InputTypesを設定
|
---|
| 304 | /// </summary>
|
---|
| 305 | public void PrepareInputInfo()
|
---|
| 306 | {
|
---|
| 307 | if (m_InputTypes != null)
|
---|
| 308 | return;
|
---|
| 309 |
|
---|
| 310 | m_InputTypes = new List<PropertyInputInfo>();
|
---|
| 311 |
|
---|
| 312 | JsonPropertyInfo epi = m_PropertyInfo;
|
---|
| 313 | if ((epi == null) || !epi.primitive)
|
---|
| 314 | return;
|
---|
| 315 |
|
---|
| 316 | ValueRange valueRange = ValueRange.Parse(epi.valueDescription, epi);
|
---|
| 317 | if (!String.IsNullOrEmpty(epi.initialValue))
|
---|
| 318 | valueRange.InitailValue = epi.initialValue;
|
---|
| 319 |
|
---|
| 320 | if (valueRange.Values.Count > 0) {
|
---|
| 321 | PropertySelectInput pii;
|
---|
| 322 | pii = new PropertySelectInput();
|
---|
| 323 | foreach (var option in valueRange.Values)
|
---|
| 324 | pii.Option.Add(option.Val, option.Disp);
|
---|
| 325 | m_InputTypes.Add(pii);
|
---|
| 326 | }
|
---|
| 327 | foreach (var range in valueRange.Ranges) {
|
---|
| 328 | PropertyRangeInput pii;
|
---|
| 329 | pii = new PropertyRangeInput();
|
---|
| 330 | pii.Minimum = (int)range.Min;
|
---|
| 331 | pii.Maximum = (int)range.Max;
|
---|
| 332 | pii.MinDescrption = range.MinDisp;
|
---|
| 333 | pii.MaxDescrption = range.MaxDisp;
|
---|
| 334 | m_InputTypes.Add(pii);
|
---|
| 335 | }
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | public static GetClassInfoHandler GetClassInfo;
|
---|
| 341 | private List<NodeInfo> m_NodeList = new List<NodeInfo>();
|
---|
| 342 |
|
---|
| 343 | public DeviceController(List<NodeInfo> nodeList)
|
---|
| 344 | {
|
---|
| 345 | m_NodeList = nodeList;
|
---|
| 346 | base.DeviceController = this;
|
---|
| 347 | }
|
---|
| 348 |
|
---|
| 349 | public IEnumerable<NodeInfo> NodeList { get { return m_NodeList; } }
|
---|
| 350 | /// <summary>
|
---|
| 351 | /// プロパティ値を設定
|
---|
| 352 | /// </summary>
|
---|
| 353 | /// <param name="response"></param>
|
---|
| 354 | /// <returns></returns>
|
---|
| 355 | public bool RecvResponse(WebApiEchonetMessage response)
|
---|
| 356 | {
|
---|
| 357 | NodeInfo ni;
|
---|
| 358 | DeviceInfo di;
|
---|
| 359 |
|
---|
| 360 | GetDevice(response.sender, response.seoj, out ni, out di);
|
---|
| 361 | if (ni == null) {
|
---|
| 362 | Debug.WriteLine("ni == null");
|
---|
| 363 | return false;
|
---|
| 364 | }
|
---|
| 365 | if (di == null) {
|
---|
| 366 | Debug.WriteLine("di == null");
|
---|
| 367 | return false;
|
---|
| 368 | }
|
---|
| 369 | foreach (var prop in response.properties) {
|
---|
| 370 | if (prop.edt.Length > 0) {
|
---|
| 371 | //プロパティ値を採用
|
---|
| 372 | di.SetPropertyData(prop.epc, prop.GetEdt());
|
---|
| 373 | }
|
---|
| 374 | else {
|
---|
| 375 | // プロパティ値書き込み応答の場合
|
---|
| 376 | if (response.esv == /*ESV_SET_RES*/0x71) {
|
---|
| 377 | // 入力値を採用
|
---|
| 378 | di.AdoptInputData(prop.epc);
|
---|
| 379 | }
|
---|
| 380 | }
|
---|
| 381 | }
|
---|
| 382 |
|
---|
| 383 | return true;
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 | public void RecvResponse(DeviceInfo di, byte esv, byte epc, byte[] edt)
|
---|
| 387 | {
|
---|
| 388 | if (edt.Length > 0) {
|
---|
| 389 | // プロパティ値を設定
|
---|
| 390 | di.SetPropertyData(epc, edt);
|
---|
| 391 | }
|
---|
| 392 | else {
|
---|
| 393 | // プロパティ値書き込み応答の場合
|
---|
| 394 | if (esv == /*ESV_SET_RES*/0x71) {
|
---|
| 395 | // 入力値を採用
|
---|
| 396 | di.AdoptInputData(epc);
|
---|
| 397 | }
|
---|
| 398 | }
|
---|
| 399 | }
|
---|
| 400 | /// <summary>
|
---|
| 401 | /// 機器を取得
|
---|
| 402 | /// </summary>
|
---|
| 403 | /// <param name="nodid"></param>
|
---|
| 404 | /// <param name="eoj"></param>
|
---|
| 405 | /// <param name="nod"></param>
|
---|
| 406 | /// <param name="obj"></param>
|
---|
| 407 | private void GetDevice(ENOD_ID nodid, T_ECN_EOJ eoj, out NodeInfo nod, out DeviceInfo obj)
|
---|
| 408 | {
|
---|
| 409 | obj = null;
|
---|
| 410 | nod = FindNode(nodid);
|
---|
| 411 |
|
---|
| 412 | if (nod != null) {
|
---|
| 413 | // ノードプロファイルの場合
|
---|
| 414 | if ((eoj.x1 == T_ECN_EOJ.X1_PROFILE)
|
---|
| 415 | && (eoj.x2 == T_ECN_EOJ.X2_NODE_PROFILE)) {
|
---|
| 416 | obj = nod.Profile;
|
---|
| 417 | }
|
---|
| 418 | // 機器オブジェクトの場合
|
---|
| 419 | else {
|
---|
| 420 | obj = FindDevice(nod, eoj);
|
---|
| 421 | }
|
---|
| 422 | }
|
---|
| 423 | }
|
---|
| 424 | /// <summary>
|
---|
| 425 | ///ノードを取得
|
---|
| 426 | /// </summary>
|
---|
| 427 | /// <param name="enodid"></param>
|
---|
| 428 | /// <returns></returns>
|
---|
| 429 | private NodeInfo FindNode(ENOD_ID enodid)
|
---|
| 430 | {
|
---|
| 431 | NodeInfo ni = null;
|
---|
| 432 |
|
---|
| 433 | switch (enodid) {
|
---|
| 434 | case ENOD_ID.MULTICAST_ID:
|
---|
| 435 | case ENOD_ID.LOCAL_ID:
|
---|
| 436 | ni = m_NodeList[0];
|
---|
| 437 | break;
|
---|
| 438 | default:
|
---|
| 439 | ni = m_NodeList.FirstOrDefault(p => p.NodeId == enodid);
|
---|
| 440 | break;
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | return ni;
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 | private DeviceInfo FindDevice(NodeInfo ni, T_ECN_EOJ eoj)
|
---|
| 447 | {
|
---|
| 448 | foreach (DeviceInfo di in ni.Devices) {
|
---|
| 449 | if ((di.ClassGroupCode == eoj.x1)
|
---|
| 450 | && (di.ClassCode == eoj.x2)
|
---|
| 451 | && (di.InstanceCode == eoj.x3))
|
---|
| 452 | return di;
|
---|
| 453 | }
|
---|
| 454 |
|
---|
| 455 | return null;
|
---|
| 456 | }
|
---|
| 457 | }
|
---|
| 458 | }
|
---|