UdonLibrary 1.0.0
機械システム研究部 C++ ライブラリ
読み取り中…
検索中…
一致する文字列を見つけられません
Im920Normal.hpp
[詳解]
1//
2// 通常 IM920
3//
4// Copyright (c) 2022-2024 udonrobo
5//
6
7//
8// Sender --[UART]--> IM920 ~~[920MHz]~~> IM920 --[UART]--> Receiver
9// ^^^^^^ ^^^^^^^^
10//
11
12#pragma once
13
14#include "IIm920.hpp"
15
20
21namespace Udon
22{
23
25 class Im920
26 : public IIm920
27 {
28 HardwareSerial& uart;
29
30 Im920Node* txNode;
31 Im920Node* rxNode;
32
33 bool twoWayNum;
34 uint32_t sendMitMs;
35 uint32_t receiveDeadTime;
36
37 public:
38 Im920(HardwareSerial& uart, bool twoWayNum = false)
39 : uart(uart)
40 , twoWayNum(twoWayNum)
41 , sendMitMs()
42 , receiveDeadTime()
43 {
44 }
45
48 operator bool() const override
49 {
50 switch (getTransmitMode())
51 {
52 case TransmitMode::Send:
53 return uart && (millis() - sendMitMs < 1000);
54 case TransmitMode::Receive:
55 return uart && (millis() - receiveDeadTime < 1000);
56 case TransmitMode::TwoWay:
57 return uart && (2 * millis() - (sendMitMs + receiveDeadTime) < 1000);
58 default:
59 return false;
60 }
61 }
62
65 void begin(uint8_t channel);
66
67 void update()
68 {
69 switch (getTransmitMode())
70 {
71 case TransmitMode::Send:
72 sendUpdate();
73 break;
74 case TransmitMode::Receive:
75 receiveUpdate();
76 break;
77 case TransmitMode::TwoWay:
78 twoWayUpdate();
79 break;
80 default:
81 break;
82 }
83 }
84
86 void show()
87 {
88 if (operator bool())
89 {
90 Serial.print("IM920: OK ");
91 }
92 else
93 {
94 Serial.print("IM920: NG ");
95 }
96
97 switch (getTransmitMode())
98 {
99 case TransmitMode::Send:
100 Serial.print("SendMode ");
101 break;
102 case TransmitMode::Receive:
103 Serial.print("ReceiveMode ");
104 break;
105 case TransmitMode::TwoWay:
106 Serial.print("TwoWayMode ");
107 break;
108 case TransmitMode::Empty:
109 Serial.print("Empty ");
110 break;
111 }
112 }
113
116 void joinTx(Im920Node& node) override { txNode = &node; }
117
119 void joinRx(Im920Node& node) override { rxNode = &node; }
120
121 private:
122 enum class TransmitMode
123 {
124 Send,
125 Receive,
126 TwoWay,
127 Empty,
128 };
129
131 TransmitMode getTransmitMode() const
132 {
133 if (txNode)
134 {
135 if (rxNode)
136 {
137 return TransmitMode::TwoWay;
138 }
139 else
140 {
141 return TransmitMode::Send;
142 }
143 }
144 else if (rxNode)
145 {
146 return TransmitMode::Receive;
147 }
148 else
149 {
150 return TransmitMode::Empty;
151 }
152 }
153
154 void sendUpdate()
155 {
156 uart.print("TXDA ");
157
158 Udon::BitPack(txNode->data, txNode->data + txNode->size, [this](uint8_t data)
159 { uart.write(data); });
160
161 uart.print("\r\n");
162 }
163
164 bool receiveUpdate()
165 {
166 // header = [Dummy: 2byte] + [,] + [Node number: 4byte] + [,] + [RSSI: 2byte] + [:]
167 constexpr int HeaderSize = 2 + 1 + 4 + 1 + 2 + 1;
168
169 // footer = [\r] + [\n]
170 constexpr int FooterSize = 1 + 1;
171
172 // FrameSize = header + data + footer
173 const int FrameSize = HeaderSize + Udon::BitPackedSize(rxNode->size) + FooterSize;
174
175 // 受信バッファにデータがない場合は何もしない
176 if (uart.available() < FrameSize)
177 {
178 return false;
179 }
180
181 // ヘッダー読み捨て
182 for (int i = 0; i < HeaderSize; ++i)
183 {
184 uart.read();
185 }
186
187 // データ読み込み
188 if (not Udon::BitUnpack(rxNode->data, rxNode->data + rxNode->size, [this]() -> uint8_t
189 { return uart.read(); }))
190 {
191 // 先頭バイトの MSB が 1 でない場合はデータが壊れているので読み捨て
192 while (uart.available())
193 {
194 uart.read();
195 }
196 return false;
197 }
198
199 // フッター読み捨て
200 for (int i = 0; i < FooterSize; ++i)
201 {
202 uart.read();
203 }
204
205 // バッファに残っているデータを読み捨て
206 while (uart.available())
207 {
208 uart.read();
209 }
210
211 rxNode->transmitMs = millis();
212
213 return true;
214 }
215
216 void twoWayUpdate()
217 {
218 // transTime =[内部処理時間:10~20ms]+[キャリアセンス:初回5.2ms 連続通信時0.5ms]+[不要データの通信:3.2ms]+[バイトごとの送信時間:0.16ms]
219 const double sendTime = 10.0 + 5.2 + 3.2 + txNode->size * 0.16;
220 const double receiveTime = 10.0 + 5.2 + 3.2 + rxNode->size * 0.16;
221
222 if (twoWayNum)
223 {
224 if (2 * millis() - (sendMitMs + receiveDeadTime) > sendTime + receiveTime)
225 { // 時間経過により再送信
226 sendUpdate();
227 }
228 if (receiveUpdate())
229 {
230 sendUpdate();
231 }
232 }
233 else
234 {
235 if (receiveUpdate())
236 {
237 sendUpdate();
238 }
239 }
240 }
241 };
242 inline void Im920::begin(uint8_t channel)
243 {
244 // ボーレート設定
245 uart.begin(115200);
246
247 // チャンネル設定
248 Udon::Printf(uart, "STCH %02d\r\n", channel);
249 delay(100);
250
251 // 送信出力[10mW]
252 uart.print("STPO 3\r\n");
253 delay(100);
254
255 // 高速通信モード[50kbps]
256 uart.print("STRT 1\r\n");
257 delay(100);
258
259 // キャラクタ入出力モード
260 uart.print("ECIO\r\n");
261 delay(1000);
262 }
263} // namespace Udon
IM920のインターフェース
Definition IIm920.hpp:31
IM920通信クラス
Definition Im920Normal.hpp:27
void update()
Definition Im920Normal.hpp:67
void begin(uint8_t channel)
通信開始
Definition Im920Normal.hpp:242
void joinRx(Im920Node &node) override
受信ノードを登録
Definition Im920Normal.hpp:119
void joinTx(Im920Node &node) override
送信ノードを登録
Definition Im920Normal.hpp:116
Im920(HardwareSerial &uart, bool twoWayNum=false)
Definition Im920Normal.hpp:38
void show()
バスの状態を表示
Definition Im920Normal.hpp:86
Definition Bit.hpp:12
void BitPack(const InputIterator begin, const InputIterator end, Functor callback)
バイト列のMSB(最上位ビット)を抽出し、7bitごとに分割してコールバック関数に渡す
Definition BitPack.hpp:23
void Printf(const char *format, Args... args)
Definition Printf.hpp:44
bool BitUnpack(OutputIterator begin, OutputIterator end, Functor callback)
7bit分割されたデータを結合する
Definition BitPack.hpp:70
constexpr size_t BitPackedSize(size_t size)
ビットパックされたデータのサイズを取得する
Definition BitPack.hpp:132
IM920ノード
Definition IIm920.hpp:20
uint32_t transmitMs
Definition IIm920.hpp:23
uint8_t * data
Definition IIm920.hpp:21
uint8_t size
Definition IIm920.hpp:22