forked from IntelRealSense/RealSenseID
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AndroidSerial.cc
150 lines (137 loc) · 4.84 KB
/
AndroidSerial.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2020-2021 Intel Corporation. All Rights Reserved.
#include "AndroidSerial.h"
#include "Logger.h"
#include "SerialPacket.h"
#include <string.h>
#include <cassert>
#include <chrono>
#include <thread>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <linux/serial.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "CyclicBuffer.h"
#include "Timer.h"
namespace RealSenseID
{
namespace PacketManager
{
static const char* LOG_TAG = "AndroidSerial";
static void ThrowAndroidError(std::string msg)
{
throw std::runtime_error(msg + ". GetLastError: " + std::to_string(errno));
}
void AndroidSerial::StartReadFromDeviceWorkingThread()
{
_worker_thread = std::thread([this]() {
const size_t read_buffer_size = 4096;
char temp_read_buffer[read_buffer_size];
while (false == _stop_read_from_device_working_thread)
{
struct usbdevfs_bulktransfer ctrl;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.ep = _read_endpoint_address;
ctrl.len = read_buffer_size;
ctrl.data = (void*)temp_read_buffer;
ctrl.timeout = 2000;
int ioctl_result = ioctl(_file_descriptor, USBDEVFS_BULK, &ctrl);
if (-1 < ioctl_result)
{
size_t ioctl_positive_result = ::abs(ioctl_result);
// LOG_DEBUG(LOG_TAG, "ioctl returned %d bytes from the device using FileDescriptor(%d) and
// ReadEndpointAddress(%d)", ioctlResult, m_FileDescriptor, m_ReadEndpointAddress);
if (ioctl_positive_result == read_buffer_size)
{
LOG_DEBUG(LOG_TAG, "ioctl returned %d. %s", errno, strerror(errno));
}
else
{
size_t actual_bytes_writen =
_read_from_device_buffer.Write(temp_read_buffer, ioctl_positive_result);
if (actual_bytes_writen != ioctl_positive_result)
{
LOG_ERROR(LOG_TAG, "Intermediate buffer out of space!");
assert(false);
}
}
}
}
});
}
SerialStatus AndroidSerial::SendBytes(const char* buffer, size_t n_bytes)
{
struct usbdevfs_bulktransfer ctrl;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.ep = _write_endpoint_address;
ctrl.len = n_bytes;
ctrl.data = (void*)buffer;
ctrl.timeout = 1000;
int number_of_bytes_sent = ioctl(_file_descriptor, USBDEVFS_BULK, &ctrl);
if (0 > number_of_bytes_sent)
{
int error_number = errno;
LOG_ERROR(LOG_TAG, "ioctl failed with error: 0x%x", error_number);
return SerialStatus::SendFailed;
}
if (n_bytes != ::abs(number_of_bytes_sent))
{
LOG_ERROR(LOG_TAG, "Error while writing to serial port");
return SerialStatus::SendFailed;
}
DEBUG_SERIAL(LOG_TAG, "[snd]", buffer, n_bytes);
return SerialStatus::Ok;
}
AndroidSerial::~AndroidSerial()
{
_stop_read_from_device_working_thread = true;
if (_worker_thread.joinable())
{
_worker_thread.join();
}
}
AndroidSerial::AndroidSerial(int file_descriptor, int read_endpoint_address, int write_endpoint_address) :
_stop_read_from_device_working_thread(false), _file_descriptor(file_descriptor),
_read_endpoint_address(read_endpoint_address), _write_endpoint_address(write_endpoint_address)
{
_stop_read_from_device_working_thread = false;
StartReadFromDeviceWorkingThread();
}
SerialStatus AndroidSerial::RecvBytes(char* buffer, size_t n_bytes)
{
if (n_bytes == 0)
{
LOG_ERROR(LOG_TAG, "Attempt to recv 0 bytes");
return SerialStatus::RecvFailed;
}
// set timeout to depend on number of bytes needed
Timer timer {std::chrono::milliseconds {200 + 4 * n_bytes}};
size_t total_bytes_read = 0;
while (!timer.ReachedTimeout())
{
char* buf_ptr = buffer + total_bytes_read;
auto last_read_result = _read_from_device_buffer.Read(buf_ptr, n_bytes - total_bytes_read);
if (last_read_result > 0)
{
total_bytes_read += last_read_result;
if (total_bytes_read >= n_bytes)
{
assert(n_bytes == total_bytes_read);
DEBUG_SERIAL(LOG_TAG, "[rcv]", buffer, total_bytes_read);
return SerialStatus::Ok;
}
}
else
{
// Allow time for writing to the buffer
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
DEBUG_SERIAL(LOG_TAG, "[rcv]", buffer, total_bytes_read);
DEBUG_SERIAL(LOG_TAG, "Timeout recv %zu bytes. Got only %zu bytes", n_bytes, total_bytes_read);
return SerialStatus::RecvTimeout;
}
} // namespace PacketManager
} // namespace RealSenseID