source: asp3_tinet_ecnl_arm/trunk/app6_hot_water_pot/src/echonet_main.c@ 364

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

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 17.2 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2014-2018 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$
36 */
37
38/*
39 * サンプルプログラム(1)の本体
40 */
41
42#include <kernel.h>
43#include <t_syslog.h>
44#include <t_stdlib.h>
45#include <sil.h>
46#include <string.h>
47#include "syssvc/serial.h"
48#include "syssvc/syslog.h"
49#include "kernel_cfg.h"
50#include "echonet_main.h"
51#include "echonet_cfg.h"
52#include "target_kernel_impl.h"
53#include "gpio_api.h"
54
55/* TODO: メーカーコードを設定 */
56#define MAKER_CODE { 0x00, 0x00, 0xB3 } /* TOPPERSプロジェクト */
57
58/* ノードプロファイルオブジェクト */
59struct ecn_cls0EF0_t node_local_profile_data = {
60 0x30, /* 動作状態 */
61 { 0x01, 0x0A, { 0x01, 0x00 } }, /* Version情報 */
62 {
63 0xFE, /* 下位通信層IDフィールド */
64 { MAKER_CODE }, /* メーカーコード */
65 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, /* ユニークID部(メーカー独自) */
66 },
67 { MAKER_CODE }, /* メーカーコード */
68};
69
70/* 電気ポットクラス */
71struct ecn_cls03B2_t electric_hot_water_pot_data = {
72 0x30, /* 動作状態 */
73 0x41, /* 湯切れ警告状態 */
74 0x41, /* 出湯状態 */
75 0x00, /* 設置場所 */
76 { 0x00, 0x00, 'C', 0x00 }, /* 規格Version情報 */
77 0x42, /* 異常発生状態 */
78 { MAKER_CODE }, /* メーカーコード */
79};
80
81/* ノードプロファイルオブジェクト */
82struct ecn_cls0EF0_t node_remote_profile_data = {
83 0x30, /* 動作状態 */
84 { 0x01, 0x0A, { 0x01, 0x00 } }, /* Version情報 */
85 {
86 0xFE, /* 下位通信層IDフィールド */
87 { MAKER_CODE }, /* メーカーコード */
88 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, /* ユニークID部(メーカー独自) */
89 },
90 { MAKER_CODE }, /* メーカーコード */
91};
92
93/* ブザークラス */
94struct ecn_cls02A0_t buzzer_data = {
95 0x30, /* 動作状態 */
96 0x00, /* 設置場所 */
97 { 0x00, 0x00, 'C', 0x00 }, /* 規格Version情報 */
98 0x42, /* 異常発生状態 */
99 { MAKER_CODE }, /* メーカーコード */
100};
101
102/* 電源LED */
103gpio_t pow_led;
104/* カラーLED */
105gpio_t led_blue, led_green, led_red;
106/* ユーザースイッチ CN16-4 */
107gpio_t sw1, sw2;
108
109/*
110 * 動作状態ON/OFF設定関数(0x30, 0x31のみ受け付け)
111 */
112int onoff_prop_set(const EPRPINIB *item, const void *src, int size, bool_t *anno)
113{
114 /* サイズが1以外は受け付けない */
115 if (size != 1)
116 return 0;
117
118 *anno = *((uint8_t*)item->exinf) != *((uint8_t*)src);
119
120 switch (*(uint8_t *)src) {
121 /* ONの場合 */
122 case 0x30:
123 *((uint8_t *)item->exinf) = *((uint8_t *)src);
124 /* LEDをON */
125 gpio_write(&pow_led, 1);
126 break;
127 /* OFFの場合 */
128 case 0x31:
129 *((uint8_t *)item->exinf) = *((uint8_t *)src);
130 /* LEDをOFF */
131 gpio_write(&pow_led, 0);
132 break;
133 /* 0x30か0x31以外は受け付けない */
134 default:
135 return 0;
136 }
137
138 return 1;
139}
140
141/*
142 * 異常発生状態設定関数(0x41, 0x42のみ受け付け)
143 */
144int alarm_prop_set(const EPRPINIB *item, const void *src, int size, bool_t *anno)
145{
146 /* サイズが1以外は受け付けない */
147 if (size != 1)
148 return 0;
149
150 *anno = *((uint8_t *)item->exinf) != *((uint8_t *)src);
151
152 switch (*(uint8_t *)src) {
153 /* 異常発生ありの場合 */
154 case 0x41:
155 /* 異常発生なしの場合 */
156 case 0x42:
157 *((uint8_t *)item->exinf) = *((uint8_t *)src);
158 break;
159 /* 0x41か0x42以外は受け付けない */
160 default:
161 return 0;
162 }
163
164 return 1;
165}
166
167/*
168 * 湯切れ警告状態設定関数
169 */
170int no_water_warning_set(const EPRPINIB *item, const void *src, int size, bool_t *anno)
171{
172 ER ret;
173 uint8_t data[1];
174
175 /* サイズが1以外は受け付けない */
176 if (size != 1)
177 return 0;
178
179 *anno = *((uint8_t*)item->exinf) != *((uint8_t*)src);
180
181 switch (*(uint8_t *)src) {
182 /* 湯切れ無しの場合 */
183 case 0x40:
184 *((uint8_t *)item->exinf) = *((uint8_t *)src);
185 /* LEDの赤をOFF */
186 gpio_write(&led_red, 0);
187 break;
188 /* 湯切れ有りの場合 */
189 case 0x41:
190 *((uint8_t *)item->exinf) = *((uint8_t *)src);
191 /* LEDの赤をON */
192 gpio_write(&led_red, 1);
193 break;
194 /* 0x40か0x41以外は受け付けない */
195 default:
196 return 0;
197 }
198
199 /* メインタスクに通知 */
200 data[0] = 0xB1;
201 ret = ecn_brk_wai(data, sizeof(data));
202 if (ret != E_OK) {
203 syslog(LOG_ERROR, "ecn_brk_wai");
204 }
205
206 return 1;
207}
208
209/*
210 * 出湯状態設定関数
211 */
212int discharge_status_set(const EPRPINIB *item, const void *src, int size, bool_t *anno)
213{
214 /* サイズが1以外は受け付けない */
215 if (size != 1)
216 return 0;
217
218 *anno = *((uint8_t*)item->exinf) != *((uint8_t*)src);
219
220 switch (*(uint8_t *)src) {
221 /* 出湯有の場合 */
222 case 0x41:
223 *((uint8_t *)item->exinf) = *((uint8_t *)src);
224 /* LEDの青をON */
225 gpio_write(&led_blue, 1);
226 break;
227 /* 出湯無の場合 */
228 case 0x42:
229 *((uint8_t *)item->exinf) = *((uint8_t *)src);
230 /* LEDの青をOFF */
231 gpio_write(&led_blue, 0);
232 break;
233 /* 0x41か0x42以外は受け付けない */
234 default:
235 return 0;
236 }
237
238 return 1;
239}
240
241static void main_initialize();
242static int main_get_timer();
243static void main_progress(int interval);
244static void main_recv_esv(T_EDATA *esv);
245static void main_break_wait(uint8_t *brkdat, int32_t len);
246static void main_timeout();
247
248/*
249 * メインタスク
250 */
251void echonet_main_task(intptr_t exinf)
252{
253 ER ret, ret2;
254 SYSTIM prev, now;
255 int timer;
256 T_EDATA *esv;
257 uint8_t brkdat[64];
258 int32_t len;
259
260 /* アプリケーションの初期化 */
261 main_initialize();
262
263 ret2 = get_tim(&now);
264 if (ret2 != E_OK) {
265 syslog(LOG_ERROR, "get_tim");
266 return;
267 }
268
269 for (;;) {
270 prev = now;
271
272 /* タイマー取得 */
273 timer = main_get_timer();
274
275 /* 応答電文待ち */
276 ret = ecn_trcv_esv(&esv, timer);
277 if ((ret != E_OK) && (ret != E_BRK) && (ret != E_TMOUT)) {
278 syslog(LOG_ERROR, "ecn_trcv_esv");
279 break;
280 }
281
282 ret2 = get_tim(&now);
283 if (ret2 != E_OK) {
284 syslog(LOG_ERROR, "get_tim");
285 break;
286 }
287
288 /* 時間経過 */
289 main_progress(now - prev);
290
291 /* Echonet電文受信の場合 */
292 if (ret == E_OK) {
293 /* Echonet電文受信処理 */
294 main_recv_esv(esv);
295
296 /* 領域解放 */
297 ret = ecn_rel_esv(esv);
298 if (ret != E_OK) {
299 syslog(LOG_ERROR, "ecn_rel_esv");
300 break;
301 }
302 }
303 /* 応答電文待ちの割り込みの場合 */
304 else if (ret == E_BRK) {
305 /* 応答電文待ちの割り込みデータ取得 */
306 ret = ecn_get_brk_dat(esv, brkdat, sizeof(brkdat), &len);
307 if (ret != E_OK) {
308 syslog(LOG_ERROR, "ecn_get_brk_dat");
309 break;
310 }
311
312 /* 応答電文待ちの割り込み処理 */
313 main_break_wait(brkdat, len);
314
315 /* 領域解放 */
316 ret = ecn_rel_esv(esv);
317 if (ret != E_OK) {
318 syslog(LOG_ERROR, "ecn_rel_esv");
319 break;
320 }
321 }
322
323 /* タイムアウト処理 */
324 main_timeout();
325 }
326}
327
328void echonet_change_netif_link(uint8_t link_up, uint8_t up)
329{
330 ER ret;
331
332 if (link_up == 0)
333 return;
334
335 if (up) {
336 /* インスタンスリスト通知の送信 */
337 ret = ecn_ntf_inl();
338 if (ret != E_OK) {
339 syslog(LOG_ERROR, "ecn_ntf_inl");
340 }
341 }
342
343 /* メインタスクに通知 */
344 uint8_t data[2];
345 data[0] = 0x01;
346 data[1] = up ? 0x01 : 0x02;
347 ret = ecn_brk_wai(data, sizeof(data));
348 if (ret != E_OK) {
349 syslog(LOG_ERROR, "ecn_brk_wai");
350 return;
351 }
352}
353
354enum main_state_t {
355 main_state_start,
356 main_state_idle,
357 main_state_search,
358 main_state_wait_res,
359};
360
361int main_timer = TMO_FEVR;
362enum main_state_t main_state = main_state_start;
363int main_retry;
364
365int main_btn_timer = TMO_FEVR;
366
367bool_t main_btn1_state;
368int main_btn1_count = 0;
369bool_t main_btn2_state;
370int main_btn2_count = 0;
371
372/*
373 * 初期化
374 */
375static void main_initialize()
376{
377 uint8_t btn1, btn2;
378
379 /* LEDの初期化 */
380 gpio_init_out(&pow_led, LED_USER);
381 gpio_init_out(&led_blue, LED_BLUE);
382 gpio_init_out(&led_green, LED_GREEN);
383 gpio_init_out(&led_red, LED_RED);
384
385 /* スイッチの初期化 */
386 gpio_init_in(&sw1, USER_BUTTON0);
387 gpio_init_in(&sw2, P1_12);
388
389 /* カラーLEDを消灯 */
390 gpio_write(&led_blue, 0);
391 gpio_write(&led_green, 0);
392 gpio_write(&led_red, 0);
393
394
395 /* ECHONETミドルウェアを起動するのを待つ */
396 main_state = main_state_start;
397 main_timer = 1000 * 1000;
398
399 /* 10ms後にボタン状態を確認 */
400 main_btn_timer = 10 * 1000;
401
402 /* ボタン状態読み込み */
403 btn1 = gpio_read(&sw1);
404 btn2 = gpio_read(&sw2);
405 main_btn1_state = btn1 != 0;
406 main_btn2_state = btn2 != 0;
407
408 /* メインタスクを起動 */
409 ER ret = act_tsk(MAIN_TASK);
410 if (ret != E_OK) {
411 syslog(LOG_ERROR, "act_tsk");
412 }
413}
414
415/*
416 * タイマー取得
417 */
418static int main_get_timer()
419{
420 int result = main_timer;
421
422 if ((result == TMO_FEVR)
423 || ((main_btn_timer != TMO_FEVR) && (main_btn_timer < result))) {
424 result = main_btn_timer;
425 }
426
427 return result;
428}
429
430/*
431 * 時間経過
432 */
433static void main_progress(int interval)
434{
435 if (main_timer != TMO_FEVR) {
436 main_timer -= interval;
437 if (main_timer < 0) {
438 main_timer = 0;
439 }
440 }
441
442 if (main_btn_timer != TMO_FEVR) {
443 main_btn_timer -= interval;
444 if (main_btn_timer < 0) {
445 main_btn_timer = 0;
446 }
447 }
448}
449
450/*
451 * Echonet電文受信処理
452 */
453static void main_recv_esv(T_EDATA *esv)
454{
455 ER ret;
456 ID eobjid;
457 uint8_t epc;
458 uint8_t pdc;
459 uint8_t p_edt[256];
460 T_ENUM_EPC enm;
461
462 eobjid = ecn_get_eobj(esv);
463 if (eobjid == EOBJ_NULL) {
464 syslog(LOG_ERROR, "ecn_get_eobj");
465 return;
466 }
467
468 ret = ecn_itr_ini(&enm, esv);
469 if (ret != E_OK) {
470 syslog(LOG_ERROR, "ecn_itr_ini");
471 return;
472 }
473
474 for (;;) {
475 while ((ret = ecn_itr_nxt(&enm, &epc, &pdc, p_edt)) == E_OK) {
476 switch (epc) {
477 case 0xB1:
478 switch (main_state) {
479 /* プロパティ通知応答待ちの場合 */
480 case main_state_wait_res:
481 /* プロパティ通知応答のみ処理 */
482 if ((esv->hdr.edata.esv == ESV_INFC_RES) && (eobjid == BUZZER_NODE_EOBJ)) {
483 /* 応答受信 */
484 main_state = main_state_idle;
485 main_timer = TMO_FEVR;
486 }
487 break;
488 }
489 break;
490 case 0xD6:
491 switch (main_state) {
492 case main_state_search:
493 if (eobjid == BUZZER_NODE_EOBJ) {
494 /* ブザー検索完了 */
495 main_state = main_state_idle;
496 main_timer = TMO_FEVR;
497 }
498 break;
499 }
500 break;
501 }
502 }
503 if (ret != E_BOVR) {
504 syslog(LOG_ERROR, "ecn_itr_nxt");
505 break;
506 }
507 if (enm.is_eof)
508 break;
509 }
510}
511
512/*
513 * 応答電文待ちの割り込み処理
514 */
515static void main_break_wait(uint8_t *brkdat, int32_t len)
516{
517 ER ret;
518 T_EDATA *esv;
519
520 if (brkdat[0] == 0x01) {
521 // Link up/down
522 return;
523 }
524
525 switch (main_state) {
526 case main_state_idle:
527 case main_state_wait_res:
528 if ((len >= 1) && (*brkdat == 0xB1)) {
529 /* ブザーに湯切れ警告状態通知 */
530 ret = ecn_esv_infc(&esv, BUZZER_NODE_EOBJ, ELECTRIC_HOT_WATER_POT_EOBJ, 0xB1);
531 if (ret != E_OK) {
532 syslog(LOG_ERROR, "ecn_esv_infc");
533 return;
534 }
535
536 /* 電文送信 */
537 ret = ecn_snd_esv(esv);
538 if (ret != E_OK) {
539 syslog(LOG_ERROR, "ecn_snd_esv");
540 }
541
542 /* ブザーからの応答待ち(タイムアウト1秒、リトライ3回) */
543 main_state = main_state_wait_res;
544 main_timer = 1000 * 1000;
545 main_retry = 3;
546 }
547 break;
548 }
549}
550
551static void main_ontimer();
552static void main_btn_ontimer();
553
554/*
555 * タイムアウト処理
556 */
557static void main_timeout()
558{
559 if (main_timer == 0) {
560 main_ontimer();
561 }
562
563 if (main_btn_timer == 0) {
564 main_btn_ontimer();
565 }
566}
567
568static void main_search();
569
570static void main_ontimer()
571{
572 ER ret;
573 T_EDATA *esv;
574
575 switch (main_state) {
576 case main_state_start:
577 /* ECHONETミドルウェアを起動 */
578 ret = ecn_sta_svc();
579 if (ret != E_OK) {
580 syslog(LOG_ERROR, "ecn_sta_svc");
581 }
582
583 /* 1秒後にブザーを検索 */
584 main_state = main_state_search;
585 main_timer = 1000 * 1000;
586 break;
587 case main_state_idle:
588 syslog(LOG_ERROR, "timeout faild on main_state_idle");
589 main_timer = TMO_FEVR;
590 break;
591 case main_state_search:
592 /* ブザー再検索 */
593 main_search();
594 main_state = main_state_search;
595 main_timer = 5000 * 1000;
596 break;
597 case main_state_wait_res:
598 /* リトライアウトの場合 */
599 if (main_retry == 0) {
600 /* あきらめる */
601 main_state = main_state_idle;
602 main_timer = TMO_FEVR;
603 break;
604 }
605
606 /* ブザーに湯切れ警告状態通知を再送 */
607 ret = ecn_esv_infc(&esv, BUZZER_NODE_EOBJ, ELECTRIC_HOT_WATER_POT_EOBJ, 0xB1);
608 if (ret != E_OK) {
609 syslog(LOG_ERROR, "ecn_esv_infc");
610 main_state = main_state_idle;
611 main_timer = TMO_FEVR;
612 return;
613 }
614
615 /* 電文送信 */
616 ret = ecn_snd_esv(esv);
617 if (ret != E_OK) {
618 syslog(LOG_ERROR, "ecn_snd_esv");
619 main_state = main_state_idle;
620 main_timer = TMO_FEVR;
621 return;
622 }
623
624 /* 応答待ち */
625 main_state = main_state_wait_res;
626 main_timer = 1000 * 1000;
627 main_retry--;
628 break;
629 }
630}
631
632static void main_search()
633{
634 ER ret;
635 T_EDATA *esv;
636
637 /* ブザー検索 */
638 ret = ecn_esv_inf_req(&esv, EOBJ_NULL, 0xD6);
639 if (ret != E_OK) {
640 syslog(LOG_ERROR, "ecn_esv_inf_req");
641 return;
642 }
643
644 /* 電文送信 */
645 ret = ecn_snd_esv(esv);
646 if (ret != E_OK) {
647 syslog(LOG_ERROR, "ecn_snd_esv");
648 }
649}
650
651static void main_btn1_change(bool_t push);
652static void main_btn2_change(bool_t push);
653
654static void main_btn_ontimer()
655{
656 uint8_t btn1, btn2;
657
658 /* 10ms後にボタン状態を確認 */
659 main_btn_timer = 10 * 1000;
660
661 /* ボタン状態読み込み */
662 btn1 = gpio_read(&sw1);
663 btn2 = gpio_read(&sw2);
664
665 /* ボタン1の処理 */
666 if ((btn1 != 0) && !main_btn1_state) {
667 main_btn1_count++;
668 if (main_btn1_count > 10) {
669 main_btn1_count = 0;
670 main_btn1_state = true;
671
672 main_btn1_change(true);
673 }
674 }
675 else if ((btn1 == 0) && main_btn1_state) {
676 main_btn1_count++;
677 if (main_btn1_count > 10) {
678 main_btn1_count = 0;
679 main_btn1_state = false;
680
681 main_btn1_change(false);
682 }
683 }
684
685 /* ボタン2の処理 */
686 if ((btn2 != 0) && !main_btn2_state) {
687 main_btn2_count++;
688 if (main_btn2_count > 10) {
689 main_btn2_count = 0;
690 main_btn2_state = true;
691
692 main_btn2_change(true);
693 }
694 }
695 else if ((btn2 == 0) && main_btn2_state) {
696 main_btn2_count++;
697 if (main_btn2_count > 10) {
698 main_btn2_count = 0;
699 main_btn2_state = false;
700
701 main_btn2_change(false);
702 }
703 }
704}
705
706bool_t main_no_wather;
707
708/*
709 * ボタン1状態変化処理
710 */
711static void main_btn1_change(bool_t push)
712{
713 ER ret;
714 T_EDATA *esv;
715 uint8_t p_edt[1];
716
717 /* 押されて戻った時に処理する */
718 if (push)
719 return;
720
721 /* 湯切れ警告状態 */
722 main_no_wather = !main_no_wather;
723
724 p_edt[0] = main_no_wather ? 0x41 : 0x40;
725
726 /* プロパティ設定電文作成 */
727 ret = ecn_esv_seti(&esv, ELECTRIC_HOT_WATER_POT_EOBJ, 0xB1, 1, p_edt);
728 if (ret != E_OK) {
729 syslog(LOG_ERROR, "ecn_esv_seti");
730 return;
731 }
732
733 /* 電文送信 */
734 ecn_snd_esv(esv);
735 if (ret != E_OK) {
736 syslog(LOG_ERROR, "ecn_snd_esv");
737 }
738}
739
740/*
741 * ボタン2状態変化処理
742 */
743static void main_btn2_change(bool_t push)
744{
745 ER ret;
746 T_EDATA *esv;
747 uint8_t p_edt[1];
748
749 /* 出湯操作状態(押している時が出湯あり、押していない時は出湯なし) */
750 p_edt[0] = push ? 0x41 : 0x42;
751
752 /* プロパティ設定電文作成 */
753 ret = ecn_esv_seti(&esv, ELECTRIC_HOT_WATER_POT_EOBJ, 0xE2, 1, p_edt);
754 if (ret != E_OK) {
755 syslog(LOG_ERROR, "ecn_esv_seti");
756 return;
757 }
758
759 /* 電文送信 */
760 ecn_snd_esv(esv);
761 if (ret != E_OK) {
762 syslog(LOG_ERROR, "ecn_snd_esv");
763 }
764}
Note: See TracBrowser for help on using the repository browser.