JJYReceiver.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. from Debug import Debug
  2. from machine import Pin
  3. from machine import RTC
  4. import utime as time
  5. from JJYDecoder import JJYDecoder
  6. from micropython import schedule
  7. from machine import Timer
  8. from TimeSyncer import TimeSyncer
  9. # 定数定義
  10. STATE_IDLE = 0
  11. STATE_TRY = 1
  12. STATE_RETRY = 2
  13. class JJYReceiver(Debug,TimeSyncer):
  14. def __init__(self, jjydec: JJYDecoder, pon_pin: int, pon_pol: int, band_sel_pin:int, preferred_band:int, retry_minute=10, sync_indicator_pin=17):
  15. """
  16. コンストラクタ
  17. Args:
  18. jjydec: JJYDecoderのインスタンス
  19. pon_pin: 電源制御(PON)を接続しているGPIO番号
  20. pon_pol: 電源制御の極性(電源オンになる値)
  21. band_sel_pin: バンド選択を接続しているGPIO番号
  22. preferred_band: 優先したいバンド(1か0)
  23. retry_minute: JJYデコード試行のリトライ時間(分)
  24. sync_indicator_pin: 同期インジケーターLEDのGPIO
  25. """
  26. # JJYデコーダーにコールバックを設定
  27. self.jjy = jjydec
  28. self.jjy.add_callback(self.decoded)
  29. # 電源制御
  30. self.pon = Pin(pon_pin, Pin.OUT)
  31. # まず電源を切っておく
  32. self.pon.value(pon_pol ^ 1)
  33. self.pon_polality = pon_pol
  34. # バンド選択
  35. self.band_select = Pin(band_sel_pin, Pin.OUT)
  36. self.estimated_band = preferred_band
  37. self.band_select.value(self.estimated_band)
  38. self.retry_count = retry_minute # リトライ分
  39. self.first_try = True # 初回試行
  40. self.try_counter = 0 # 試行カウンタ
  41. self.idle_counter = 0 # アイドリングカウンタ
  42. # 現在のステート
  43. self.state = STATE_TRY
  44. # 同期インジケーター
  45. self.sync_indicator = Pin(sync_indicator_pin,mode=Pin.OUT)
  46. self.sync_indicator.value(0) # まず消灯
  47. # タイマー
  48. self.tm = Timer()
  49. # タイマーハンドラ起動時呼び出し
  50. self._timer_handler(self.tm)
  51. def sync_start(self):
  52. """強制同期スタート"""
  53. if self.state == STATE_IDLE:
  54. self.idle_counter = 0 # カウンタリセット
  55. self.state = STATE_TRY
  56. def sync_stop(self):
  57. """同期停止"""
  58. if self.state == STATE_TRY or self.state == STATE_RETRY:
  59. self.state = STATE_IDLE
  60. self.try_counter = 0 # カウンタリセット
  61. self.idle_counter = 0
  62. self.jjy.stop() # 一旦停止
  63. self.pon.value(self.pon_polality ^ 1) # 一旦電源を切る
  64. def _tick(self, arg):
  65. """
  66. タイマー割り込みからスケジュールされる状態遷移・制御ロジック
  67. """
  68. self.dprint("--- tick %d---" % (self.idle_counter))
  69. if self.state == STATE_TRY or self.state == STATE_RETRY:
  70. if self.try_counter == 0: # 試行開始
  71. self.dprint("--- Try start ---")
  72. # JJY起動
  73. self.band_select.value(self.estimated_band) # バンド設定
  74. self.pon.value(self.pon_polality) # 電源オン
  75. self.jjy.restart()
  76. # インジケーターLED消灯
  77. self.sync_indicator.value(0)
  78. self.try_counter += 1
  79. # 試行回数を超えている
  80. if self.try_counter > self.retry_count:
  81. self.try_counter = 0 # カウンタリセット
  82. self.jjy.stop() # 一旦停止
  83. self.pon.value(self.pon_polality ^ 1) # 一旦電源を切る
  84. if self.state == STATE_TRY:
  85. self.state = STATE_RETRY
  86. self.dprint("--- Retry start ---")
  87. self.estimated_band ^= 1 # バンドを変えてみる
  88. time.sleep(5) # 少し待つ
  89. elif self.state == STATE_RETRY:
  90. self.estimated_band ^= 1 # バンドを戻す
  91. if self.first_try: # バンドを変えて試行を繰り返す
  92. self.state = STATE_TRY
  93. time.sleep(5) # 少し待つ
  94. else:
  95. self.state = STATE_IDLE # 諦める
  96. self.sync_indicator.value(0) # インジケータ消灯
  97. elif self.state == STATE_IDLE:
  98. self.idle_counter += 1
  99. if self.idle_counter >= 60: # アイドル1時間経過
  100. self.idle_counter = 0
  101. self.try_counter = 0
  102. self.state = STATE_TRY # 時間合わせの試行を開始
  103. def _timer_handler(self, t):
  104. """
  105. 1分周期のハードウェアタイマーハンドラ。
  106. MicroPythonのGCストールを避けるため、実際の処理はschedule()に委譲する。
  107. """
  108. schedule(self._tick, 0)
  109. self.tm.init(mode=Timer.ONE_SHOT, period=1000*60, callback=self._timer_handler)
  110. def decoded(self, args):
  111. """
  112. JJY信号のデコード成功時に呼ばれるコールバック
  113. """
  114. self.first_try = False
  115. self.state = STATE_IDLE # 成功したのでアイドルに切り替える
  116. self.try_counter = 0 # カウンタリセット
  117. self.idle_counter = 0
  118. self.dprint("--- Succeeded JJY signal decode ---")
  119. # インジケーター点灯
  120. self.sync_indicator.value(1)
  121. # 電源を切る
  122. self.jjy.stop()
  123. self.pon.value(self.pon_polality ^ 1)