source: EcnlProtoTool/trunk/webapp/webmrbc/App.cs@ 287

Last change on this file since 287 was 287, checked in by coas-nagasima, 7 years ago

ファイルヘッダーコメントを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csharp
File size: 13.4 KB
Line 
1/*
2 * TOPPERS/ECNL Prototyping tool
3 *
4 * Copyright (C) 2017 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: App.cs 287 2017-05-05 14:22:23Z coas-nagasima $
36 */
37using System;
38using System.Collections.Generic;
39using System.Linq;
40using Bridge;
41using Bridge.Html5;
42using Bridge.jQuery2;
43
44namespace WebMrbc
45{
46 delegate bool jQueryKeyboardHandler(jQueryKeyboardEvent e);
47
48 public static class App
49 {
50 public static Mruby Module;
51 public static Terminal Term;
52 public static AceEditor CodeEditor;
53 public static TargetBoard TargetBoard;
54 public static bool changedAfterTranslating;
55 public static bool translating;
56 public static JsonClassInfo NodeProfileClass;
57 public static JsonClassGroupInfo[] ClassGroups;
58 public static JsonPropertyInfo[] BaseObjectPropertyList;
59 public static string ArduinoToolbox;
60 public static string EcnlToolbox;
61
62 [Ready]
63 public static void Main()
64 {
65 Script.Write("Number.isFinite = Number.isFinite || function(any) { return typeof any === 'number' && isFinite(any); }");
66 Script.Write("Number.isNaN = Number.isNaN || function(any) { return typeof any === 'number' && isNaN(any); }");
67
68 App.TargetBoard = new GrPeach();
69 Collections.ClassWorkspaces = new Collection<IClassWorkspace>();
70 Views.ClassSelectorView = new ClassSelectorView();
71 Views.ClassSelectorView.SetCollection(Collections.ClassWorkspaces);
72 Views.EObjectModalView = new EObjectModalView();
73 Views.MainMenuView = new MainMenuView();
74
75 var termElement = Document.GetElementById("term");
76 Term = new Terminal(new TerminalOption() {
77 cols = 80,
78 rows = 24,
79 useStyle = true,
80 screenKeys = true,
81 cursorBlink = false
82 });
83 Term.on("data", new Action<object>((data) => {
84 if (Module != null && Module["stdin"] != null)
85 Module.stdin(data);
86 }));
87 Term.on("title", new Action<string>((title) => {
88 Document.Title = title;
89 }));
90
91 Term.open(termElement);
92
93 CodeEditor = ace.edit("text-editor");
94 Window.Set("textEditor", CodeEditor);
95 CodeEditor.setTheme("ace/theme/twilight");
96 CodeEditor.setShowInvisibles(true);
97 CodeEditor.gotoLine(0, 0);
98 CodeEditor.On("change", new Action(() => {
99 if (!translating) {
100 changedAfterTranslating = true;
101 }
102 }));
103 var session = CodeEditor.getSession();
104 session.setMode("ace/mode/ruby");
105 session.setTabSize(2);
106 session.setUseSoftTabs(false);
107
108 var statusElement = Document.GetElementById("status");
109 var progressElement = Document.GetElementById("progress");
110 var spinnerElement = Document.GetElementById("spinner");
111
112 statusElement.InnerHTML = "Downloading...";
113
114 jQuery.Ready(() => {
115 InitClassGroups((result) => {
116 if (result) {
117 Views.EObjectModalView.InitClassGroups();
118 }
119 InitArduinoToolbox((result1) => {
120 InitEcnlToolbox((result2) => {
121 if (result1 && result2) {
122 AddMainLoop();
123 AddEcnlTask();
124 AddENode();
125 }
126 statusElement.InnerHTML = "";
127 spinnerElement.Style.Display = Display.None;
128 });
129 });
130 });
131 });
132 }
133
134 public static void InitClassGroups(Action<bool> action)
135 {
136 jQuery.Ajax(new AjaxOptions() {
137 Url = "echonet_objects.json",
138 Success = (data, textStatus, request) => {
139 ClassGroupsSuccess(data, textStatus, request);
140 action?.Invoke(true);
141 },
142 Error = (request, textStatus, error) => {
143 AjaxError(request, textStatus, error);
144 action?.Invoke(false);
145 }
146 });
147 }
148
149 private static void ClassGroupsSuccess(object data, string textStatus, jqXHR request)
150 {
151 var _deviceInfo = (dynamic)((data.GetType() == typeof(string)) ? jQuery.ParseJSON((string)data) : data);
152 var profProps = new JsonPropertyInfo[0];
153 foreach (var property in _deviceInfo.baseProfilePropertyList) {
154 profProps.Push(new JsonPropertyInfo(property));
155 }
156 var objProps = new JsonPropertyInfo[0];
157 foreach (var property in _deviceInfo.baseObjectPropertyList) {
158 objProps.Push(new JsonPropertyInfo(property));
159 }
160 BaseObjectPropertyList = objProps;
161
162 var classGroups = new JsonClassGroupInfo[0];
163 foreach (var _item in _deviceInfo.classGroupList) {
164 var item = new JsonClassGroupInfo(_item);
165 classGroups.Push(item);
166 var classes = new JsonClassInfo[0];
167 foreach (var _cls in _item.classList) {
168 var cls = new JsonClassInfo(_cls);
169 cls.classGroup = item;
170 classes.Push(cls);
171 var properties = new JsonPropertyInfo[0];
172 foreach (var property in _cls.propertyList) {
173 properties.Push(new JsonPropertyInfo(property));
174 }
175 if ((item.classGroupCode == 0xE) && (cls.classCode == 0xF0)) {
176 cls.properties = (JsonPropertyInfo[])profProps.Concat(properties);
177 NodeProfileClass = cls;
178 }
179 else {
180 cls.properties = properties;
181 }
182 }
183 item.classes = classes;
184 }
185 ClassGroups = classGroups;
186 }
187
188 public static void InitArduinoToolbox(Action<bool> action)
189 {
190 jQuery.Ajax(new AjaxOptions() {
191 Url = "arduino_toolbox.xml",
192 DataType = "text",
193 Success = (data, textStatus, request) => {
194 ArduinoToolbox = (string)data;
195 action?.Invoke(true);
196 },
197 Error = (request, textStatus, error) => {
198 AjaxError(request, textStatus, error);
199 action?.Invoke(false);
200 }
201 });
202 }
203
204 public static void InitEcnlToolbox(Action<bool> action)
205 {
206 jQuery.Ajax(new AjaxOptions() {
207 Url = "ecnl_toolbox.xml",
208 DataType = "text",
209 Success = (data, textStatus, request) => {
210 EcnlToolbox = (string)data;
211 action?.Invoke(true);
212 },
213 Error = (request, textStatus, error) => {
214 AjaxError(request, textStatus, error);
215 action?.Invoke(false);
216 }
217 });
218 }
219
220 private static void AjaxError(jqXHR request, string textStatus, string error)
221 {
222 }
223
224 /// <summary>
225 /// テキスト入力欄のEnter(Return)キーを無視する
226 /// </summary>
227 /// <param name="el"></param>
228 /// <returns></returns>
229 static jQuery ignoreEnterKey(jQuery el)
230 {
231 return el.Find("input[type=text]").KeyPress(new jQueryKeyboardHandler((e) => {
232 if (e == null)
233 e = (jQueryKeyboardEvent)Window.Get("Event");
234 if (e.KeyCode == 13)
235 return false;
236 else
237 return true;
238 }));
239 }
240
241 private static void AddMainLoop()
242 {
243 var view = Views.MainMenuView.NewBlocklyView("MainLoop");
244 var workspace = new MainLoopWorkspace(view);
245 Collections.MainLoopWorkspace = workspace;
246 Collections.ClassWorkspaces.Add(workspace);
247 Views.ClassSelectorView.SelectClassWorkspace(workspace);
248 view.ReloadToolbox(workspace);
249 }
250
251 private static void AddEcnlTask()
252 {
253 var identifier = Collections.ClassWorkspaces.UniqueName("EcnlTask");
254 var view = Views.MainMenuView.NewBlocklyView(identifier);
255 var workspace = new EcnlTaskWorkspace(view);
256 Collections.EcnlTaskWorkspace = workspace;
257 Collections.ClassWorkspaces.Add(workspace);
258 Views.ClassSelectorView.SelectClassWorkspace(workspace);
259 view.ReloadToolbox(workspace);
260 }
261
262 private static void AddENode()
263 {
264 var identifier = Collections.ClassWorkspaces.UniqueName("LocalNode");
265 var localNode = new JsonNodeInfo(NodeProfileClass, identifier, "local");
266 var properties = new JsonPropertyInfo[0];
267 foreach (var item in localNode.type.properties) {
268 if ((item.required.Length > 0) && (item.required[0] != "NONE")) {
269 properties.Push(new JsonPropertyInfo(item));
270 }
271 }
272 localNode.properties = properties;
273 var view = Views.MainMenuView.NewBlocklyView(localNode.identifier);
274 var workspace = new ENodeWorkspace(view, localNode);
275 Collections.LocalNode = workspace;
276 Collections.ClassWorkspaces.Add(workspace);
277 Views.ClassSelectorView.SelectClassWorkspace(workspace);
278 view.BlockCreated += workspace.OnBlockCreated;
279 view.BlockDeleted += workspace.OnBlockDeleted;
280 view.BlockChanged += workspace.OnBlockChanged;
281 view.BlockMoveed += workspace.OnBlockMoveed;
282 view.ReloadToolbox(workspace);
283 }
284
285 internal static void NewItem(Action<IClassWorkspace> callback)
286 {
287 var identifier = Collections.ClassWorkspaces.UniqueName("Kaden");
288 var eobject = new JsonObjectInfo(App.NodeProfileClass, identifier);
289 var properties = new JsonPropertyInfo[0];
290 if ((eobject.type.classGroup.classGroupCode != 0x0E)
291 && (eobject.type.classCode != 0xF0)) {
292 foreach (var item in App.BaseObjectPropertyList) {
293 if ((item.required.Length > 0) && (item.required[0] != "NONE")) {
294 properties.Push(new JsonPropertyInfo(item));
295 }
296 }
297 }
298 foreach (var item in eobject.type.properties) {
299 if ((item.required.Length > 0) && (item.required[0] != "NONE")) {
300 properties.Push(new JsonPropertyInfo(item));
301 }
302 }
303 eobject.properties = properties;
304 var view = Views.MainMenuView.NewBlocklyView(eobject.identifier);
305 var workspace = new EObjectWorkspace(view, eobject);
306 view.BlockCreated += workspace.OnBlockCreated;
307 view.BlockDeleted += workspace.OnBlockDeleted;
308 view.BlockChanged += workspace.OnBlockChanged;
309 view.BlockMoveed += workspace.OnBlockMoveed;
310 callback(workspace);
311 }
312
313 internal static void RemoveItem(IClassWorkspace item)
314 {
315 Views.MainMenuView.RemoveEObjectWorkspace(item);
316 }
317
318 internal static void Write(string text)
319 {
320 Term?.write(text.Replace("\n", "\r\n"));
321 }
322
323 internal static void WriteLine(string text)
324 {
325 Term?.write(text.Replace("\n", "\r\n") + "\r\n");
326 }
327 }
328
329 public interface IClassWorkspace : IModel
330 {
331 Workspace Workspace { get; }
332 BlocklyView View { get; }
333 Ruby RubyCode { get; }
334 string GetImageUrl();
335 bool IsPreset();
336 string ToCode(string filename);
337 void Activate();
338 void Inactivate();
339 void ReloadToolbox(HTMLElement toolbox);
340 void OpenModifyView(Action<bool> callback);
341 string Template(string template);
342 }
343
344 public class Collections
345 {
346 [Name(false)]
347 internal static ENodeWorkspace LocalNode;
348 [Name(false)]
349 internal static Collection<IClassWorkspace> ClassWorkspaces;
350 [Name(false)]
351 internal static EcnlTaskWorkspace EcnlTaskWorkspace;
352 [Name(false)]
353 internal static MainLoopWorkspace MainLoopWorkspace;
354 }
355
356 public class Views
357 {
358 [Name(false)]
359 internal static MainMenuView MainMenuView;
360 [Name(false)]
361 internal static ClassSelectorView ClassSelectorView;
362 [Name(false)]
363 internal static EObjectModalView EObjectModalView;
364 }
365
366 public class HexDump
367 {
368 string text;
369
370 public HexDump(Uint8Array bytes, int width)
371 {
372 var sb = new string[0];
373
374 for (int index = 0; index < bytes.Length; index += width) {
375 sb.Push(String.Format("{0:X4} : ", index)
376 + BinBump(bytes, index, width)
377 + AsciiDump(bytes, index, width));
378 }
379
380 text = sb.Join("\n");
381 }
382
383 private string BinBump(Uint8Array bytes, int offset, int width)
384 {
385 var sb = new System.Text.StringBuilder();
386
387 for (int index = 0; index < width; index++) {
388 if (index + offset < bytes.Length) {
389 sb.AppendFormat("{0:X2} ", bytes[index + offset]);
390 }
391 else {
392 sb.Append(" ");
393 }
394 }
395
396 return sb.ToString();
397 }
398
399 private string AsciiDump(Uint8Array bytes, int index, int width)
400 {
401 var sb = "";
402
403 if (index < bytes.Length) {
404 width = System.Math.Min(width, bytes.Length - index);
405
406 sb += ": ";
407 for (int i = 0; i < width; i++) {
408 byte b = bytes[i + index];
409 if (b < 0x20)
410 sb += "\x1B[1;3;31m" + String.FromCharCode(b + 0x40) + "\x1B[0m";
411 else
412 sb += String.FromCharCode(b);
413 }
414 }
415 else {
416 sb += ": ";
417 }
418
419 return sb;
420 }
421
422 public override string ToString()
423 {
424 return text;
425 }
426 }
427}
Note: See TracBrowser for help on using the repository browser.