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