GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
serial_communication_thread.cpp
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
9
10#include "cmdio_util.h"
11#include "string_util.h"
12
13namespace {
14// 無名名前空間.このファイル内でのみ有効.
15
16static constexpr int kBaudRate = 9600; // ボーレート.Arduino側と合わせる.
17
18// COMポートの名前.
19const std::string kComName[] = {"",
20 "COM1",
21 "COM2",
22 "COM3",
23 "COM4",
24 "COM5",
25 "COM6",
26 "\\\\.\\COM7",
27 "COM8",
28 "COM9",
29 "\\\\.\\COM10",
30 "\\\\.\\COM11",
31 "\\\\.\\COM12",
32 "\\\\.\\COM13"};
33} // namespace
34
35namespace designlab {
36
38 if (!Initialize()) {
39 end_flag_ = true;
40
41 // 通信の初期化に失敗した場合は,即座に終了する.
42 return;
43 }
44
45 while (true) {
46 Sleep(static_cast<int>(
47 1000 * kThreadPeriod)); // 指定した時間だけスリープする.(ミリ秒単位)
48
49 // 読み込みを行う.
50 if (!Read()) {
51 EndThread();
52
53 // 読み込みに失敗した場合は,即座に終了する.
54 return;
55 }
56
57 // 書き込みを行う.
58 if (!Write()) {
59 EndThread();
60
61 // 書き込みに失敗した場合は,即座に終了する.
62 return;
63 }
64
65 // スレッドの終了フラグが立っている場合は,即座に終了する.
66 if (IsEnd()) {
67 return;
68 }
69 }
70}
71
72void SerialCommunicationThread::SetWriteData(const std::string& str) {
73 // 通信が開始されていない場合は,即座に終了する.
74 if (serial_handle_ == INVALID_HANDLE_VALUE) {
75 return;
76 }
77
78 // 書き込みデータを送信する.
79 boost::mutex::scoped_lock lock(mutex_);
80
81 write_data_ = str;
82}
83
85 // スレッドの排他制御を行う.
86 boost::mutex::scoped_lock lock(mutex_);
87
88 // 読み込みデータが空の場合は,空文字を返す.
89 if (read_data_.empty()) {
90 return "";
91 }
92
93 return read_data_.back();
94}
95
96std::vector<std::string> SerialCommunicationThread::GetAllReadData() const {
97 // スレッドの排他制御を行う.
98 boost::mutex::scoped_lock lock(mutex_);
99
100 return read_data_;
101}
102
104 const int num) const {
105 // スレッドの排他制御を行う.
106 boost::mutex::scoped_lock lock(mutex_);
107
108 std::vector<std::string> ret;
109
110 // 読み込みデータが空の場合は,空の配列を返す.
111 if (read_data_.empty()) {
112 return ret;
113 }
114
115 // 読み込みデータが指定した数よりも少ない場合は,全てのデータを返す.
116 if (read_data_.size() <= num) {
117 return read_data_;
118 }
119
120 // 読み込みデータが指定した数よりも多い場合は,最新のデータを返す.
121 for (int i = 0; i < num; ++i) {
122 ret.push_back(read_data_[read_data_.size() - 1 - i]);
123 }
124
125 return ret;
126}
127
128bool SerialCommunicationThread::Initialize() {
129 // 通信を開始する.Windowsでは CreateFile で COMポートを開く.
130 serial_handle_ =
131 CreateFile(kComName[kComPortNumber].c_str(), GENERIC_READ | GENERIC_WRITE,
132 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
133
134 if (serial_handle_ == INVALID_HANDLE_VALUE) {
135 return false;
136 }
137
138 // 通信の設定を行う.
139 SetupComm(serial_handle_, kBufferSize, kBufferSize); // バッファーを作る.
140 PurgeComm(serial_handle_, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR |
141 PURGE_RXCLEAR); // バッファーのクリア.
142
143 // シリアルポートの設定を行う.
144 DCB dcb;
145 GetCommState(serial_handle_, &dcb); // 現在の設定を取得.
146
147 dcb.ByteSize = 8;
148 dcb.XonChar = 0;
149 dcb.XoffChar = 0;
150 dcb.EofChar = 4;
151 dcb.EvtChar = 10;
152 dcb.BaudRate = kBaudRate;
153
154 SetCommState(serial_handle_, &dcb); // 設定を反映.
155
156 // タイムアウトの設定を行う.
157 COMMTIMEOUTS timeouts;
158 GetCommTimeouts(serial_handle_, &timeouts); // 現在の設定を取得.
159
160 timeouts.ReadIntervalTimeout = 100;
161 timeouts.ReadTotalTimeoutMultiplier = 100;
162 timeouts.ReadTotalTimeoutConstant = 100;
163 timeouts.WriteTotalTimeoutMultiplier = 0;
164 timeouts.WriteTotalTimeoutConstant = 0;
165
166 SetCommTimeouts(serial_handle_, &timeouts); // 設定を反映.
167
168 return true;
169}
170
171bool SerialCommunicationThread::Read() {
172 // 通信が開始されていない場合は,即座に終了する.
173 if (serial_handle_ == INVALID_HANDLE_VALUE) {
174 return false;
175 }
176
177 DWORD read_size = 0;
178 char read_buffer[kBufferSize] = {0};
179
180 if (!ReadFile(serial_handle_, read_buffer, kBufferSize, &read_size, NULL)) {
181 // 読み込みに失敗した場合は終了する.
182 return false;
183 }
184
185 if (read_size == 0) {
186 // 読み込みデータがない場合は終了する.
187 // 読み込み自体は成功しているため,trueを返す.
188 return true;
189 }
190
191 // 読み込んだデータを格納する.
192 std::string read_data(read_buffer, read_size);
193
194 // 読み込んだデータを改行コードで分割する.
195 std::vector<std::string> split_data = string_util::Split(read_data, "\n");
196
197 // 分割したデータを読み込みデータに追加する.
198 {
199 // スレッドの排他制御を行う.
200 boost::mutex::scoped_lock lock(mutex_);
201
202 for (const auto& data : split_data) {
203 // 空文字の場合は追加しない.
204 if (data.empty()) {
205 continue;
206 }
207
208 // 読み込みデータに追加する.
209 read_data_.push_back(data);
210 }
211 }
212
213 return true;
214}
215
216bool SerialCommunicationThread::Write() {
217 // 通信が開始されていない場合は,即座に終了する.
218 if (serial_handle_ == INVALID_HANDLE_VALUE) {
219 return false;
220 }
221
222 // 書き込みデータがない場合は,即座に終了する.
223 if (write_data_ == "") {
224 return true;
225 }
226
227 DWORD write_size = 0;
228
229 if (!WriteFile(serial_handle_, write_data_.c_str(),
230 static_cast<DWORD>(write_data_.size()), &write_size, NULL)) {
231 // 書き込みに失敗した場合は終了する.
232 return false;
233 }
234
235 if (write_size == 0) {
236 // 書き込みデータがない場合は終了する.
237 // 書き込み自体は成功しているため,trueを返す.
238 return true;
239 }
240
241 // 書き込みデータをクリアする.
242 write_data_ = "";
243
244 return true;
245}
246
247} // namespace designlab
void SetWriteData(const std::string &str)
指定した文字列をシリアル通信で送信する. この時,排他制御を行う.
void EndThread()
シリアル通信のスレッドを終了する.
std::string GetTopReadData() const
シリアル通信で受信した最新の文字列を取得する. この時,排他制御を行う.
std::vector< std::string > GetAllReadData() const
シリアル通信で受信した文字列を全て取得する. この時,排他制御を行う.
std::vector< std::string > GetReadData(const int num) const
シリアル通信で受信した文字列の中から指定した数だけ取得する. この時,排他制御を行う.
std::vector< std::string > Split(const std::string &str, const std::string &separator)
文字列を分割する関数.指定した文字で文字列を分割する. 分割した結果,空白が含まれる場合や文字列がない場合は,そのまま返す. 最後が区切り文字で終わる場合は,...