1 //-----------------------------------------------------------------------------
2 //
3 //	SerialControllerImpl.cpp
4 //
5 //	WinRT Implementation of the cross-platform serial port
6 //
7 //	Copyright (c) 2015 Microsoft Corporation
8 //	All rights reserved.
9 //
10 //	SOFTWARE NOTICE AND LICENSE
11 //
12 //	This file is part of OpenZWave.
13 //
14 //	OpenZWave is free software: you can redistribute it and/or modify
15 //	it under the terms of the GNU Lesser General Public License as published
16 //	by the Free Software Foundation, either version 3 of the License,
17 //	or (at your option) any later version.
18 //
19 //	OpenZWave is distributed in the hope that it will be useful,
20 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //	GNU Lesser General Public License for more details.
23 //
24 //	You should have received a copy of the GNU Lesser General Public License
25 //	along with OpenZWave.  If not, see <http://www.gnu.org/licenses/>.
26 //
27 //-----------------------------------------------------------------------------
28 
29 #include "Defs.h"
30 #include "SerialControllerImpl.h"
31 
32 #include "platform/Log.h"
33 #include <winstring.h>
34 #include <ppltasks.h>
35 
36 using namespace OpenZWave;
37 using namespace Windows::Devices::SerialCommunication;
38 using namespace Windows::Devices::Enumeration;
39 using namespace Windows::Storage::Streams;
40 using namespace Windows::Foundation;
41 using namespace Concurrency;
42 using namespace Platform;
43 
44 //-----------------------------------------------------------------------------
45 // <SerialControllerImpl::SerialControllerImpl>
46 // Constructor
47 //-----------------------------------------------------------------------------
SerialControllerImpl(SerialController * _owner)48 SerialControllerImpl::SerialControllerImpl(	SerialController* _owner)
49 	: m_owner( _owner )
50 {
51 }
52 
53 //-----------------------------------------------------------------------------
54 // <SerialControllerImpl::~SerialControllerImpl>
55 // Destructor
56 //-----------------------------------------------------------------------------
~SerialControllerImpl()57 SerialControllerImpl::~SerialControllerImpl()
58 {
59 	Close();
60 }
61 
62 //-----------------------------------------------------------------------------
63 // <SerialControllerImpl::Close>
64 // Close the serial port
65 //-----------------------------------------------------------------------------
Close()66 void SerialControllerImpl::Close()
67 {
68 	// cancel read task
69 	m_readTaskCancelationTokenSource.cancel();
70 }
71 
72 //-----------------------------------------------------------------------------
73 // <SerialControllerImpl::Open>
74 // Open the serial port
75 //-----------------------------------------------------------------------------
Open()76 bool SerialControllerImpl::Open()
77 {
78 	Log::Write(LogLevel_Info, "Trying to open serial port %s", m_owner->m_serialControllerName.c_str());
79 
80 	try
81 	{
82 		auto selector = SerialDevice::GetDeviceSelectorFromUsbVidPid(0x10C4, 0xEA60);
83 
84 		return create_task(DeviceInformation::FindAllAsync(selector))
85 			.then([this](DeviceInformationCollection ^ devices) -> IAsyncOperation<SerialDevice ^> ^
86 		{
87 			wstring ourId(m_owner->m_serialControllerName.begin(), m_owner->m_serialControllerName.end());
88 			for (auto iterator = devices->First(); iterator->HasCurrent; iterator->MoveNext())
89 			{
90 				wstring currentId = iterator->Current->Id->Data();
91 				if (currentId.find(ourId) != wstring::npos)
92 				{
93 					return SerialDevice::FromIdAsync(iterator->Current->Id);
94 				}
95 			}
96 			return create_async([]() -> SerialDevice ^ { return nullptr; });
97 
98 		}).then([this](SerialDevice ^ device) -> bool
99 		{
100 			if (device == nullptr)
101 			{
102 				return false;
103 			}
104 			m_serialDevice = device;
105 
106 			m_serialDevice->BaudRate = m_owner->m_baud;
107 			m_serialDevice->DataBits = 8;
108 			switch (m_owner->m_stopBits)
109 			{
110 			case SerialController::StopBits::StopBits_One:
111 			{
112 				m_serialDevice->StopBits = SerialStopBitCount::One;
113 				break;
114 			}
115 			case SerialController::StopBits::StopBits_OneAndAHalf:
116 			{
117 				m_serialDevice->StopBits = SerialStopBitCount::OnePointFive;
118 				break;
119 			}
120 			case SerialController::StopBits::StopBits_Two:
121 			{
122 				m_serialDevice->StopBits = SerialStopBitCount::Two;
123 				break;
124 			}
125 			}
126 
127 			switch (m_owner->m_parity)
128 			{
129 			case SerialController::Parity::Parity_Even:
130 			{
131 				m_serialDevice->Parity = SerialParity::Even;
132 				break;
133 			}
134 			case SerialController::Parity::Parity_Mark:
135 			{
136 				m_serialDevice->Parity = SerialParity::Mark;
137 				break;
138 			}
139 			case SerialController::Parity::Parity_None:
140 			{
141 				m_serialDevice->Parity = SerialParity::None;
142 				break;
143 			}
144 			case SerialController::Parity::Parity_Odd:
145 			{
146 				m_serialDevice->Parity = SerialParity::Odd;
147 				break;
148 			}
149 			case SerialController::Parity::Parity_Space:
150 			{
151 				m_serialDevice->Parity = SerialParity::Space;
152 				break;
153 			}
154 			}
155 
156 			Windows::Foundation::TimeSpan timespan;
157 			timespan.Duration = 1;
158 			m_serialDevice->ReadTimeout = timespan;
159 
160 			StartReadTask();
161 
162 			return true;
163 		}).get();
164 	}
165 	catch (...)
166 	{
167 		return false;
168 	}
169 }
170 
171 //-----------------------------------------------------------------------------
172 // <SerialControllerImpl::StartReadTask>
173 // Start a background task which reads available data and passes it along to SerialController
174 //-----------------------------------------------------------------------------
StartReadTask()175 void SerialControllerImpl::StartReadTask()
176 {
177 	// Read serial data on background task
178 	cancellation_token token = m_readTaskCancelationTokenSource.get_token();
179 
180 	create_task([token, this]()
181 	{
182 		uint32 readBufferLength = 512;
183 		Buffer ^ buffer = ref new Buffer(readBufferLength);
184 
185 		for (;;)
186 		{
187 			try
188 			{
189 				create_task(m_serialDevice->InputStream->ReadAsync(buffer, readBufferLength, InputStreamOptions::None))
190 					.then([&, this](IBuffer ^ outBuffer)
191 				{
192 					auto reader = DataReader::FromBuffer(outBuffer);
193 					auto bytesRead = reader->UnconsumedBufferLength;
194 
195 					std::vector<uint8> byteVector(bytesRead);
196 					if (!byteVector.empty())
197 					{
198 						reader->ReadBytes(::Platform::ArrayReference<uint8>(byteVector.data(), bytesRead));
199 						m_owner->Put(byteVector.data(), bytesRead);
200 					}
201 				}).wait();
202 			}
203 			catch (Platform::Exception^ ex)
204 			{
205 				if (ex->HResult == HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED))
206 				{
207 					m_owner->Close();
208 				}
209 			}
210 
211 			if (token.is_canceled())
212 			{
213 				cancel_current_task();
214 			}
215 		}
216 	}, token);
217 }
218 
219 //-----------------------------------------------------------------------------
220 // <SerialControllerImpl::Write>
221 // Send data to the serial port
222 //-----------------------------------------------------------------------------
Write(uint8 * _buffer,uint32 _length)223 uint32 SerialControllerImpl::Write
224 (
225 	uint8* _buffer,
226 	uint32 _length
227 )
228 {
229 	uint32 retVal = 0;
230 
231 	if (m_serialDevice == nullptr)
232 	{
233 		//Error
234 		Log::Write(LogLevel_Error, "ERROR: Serial port must be opened before writing\n");
235 		return 0;
236 	}
237 
238 	DataWriter ^ writer = ref new DataWriter();
239 	writer->WriteBytes(ref new Platform::Array<uint8>(_buffer, _length));
240 	try
241 	{
242 		auto writeTask = create_task(m_serialDevice->OutputStream->WriteAsync(writer->DetachBuffer()));
243 
244 		// since the consumer of this function expects this to be synchronous, just wait here.
245 		retVal = writeTask.get();
246 	}
247 	catch (Platform::Exception^ )
248 	{
249 		//ignore - return 0
250 		retVal = 0;
251 	}
252 
253 	return retVal;
254 }
255