rogue
Loading...
Searching...
No Matches
XvcConnection.cpp
Go to the documentation of this file.
1
19
20#include <arpa/inet.h>
21#include <netinet/tcp.h>
22#include <sys/select.h>
23
24#include <cinttypes>
25#include <cstdio>
26
28
29rpx::XvcConnection::XvcConnection(int sd, JtagDriver* drv, uint64_t maxVecLen)
30 : drv_(drv),
31 maxVecLen_(maxVecLen),
32 supVecLen_(0) {
33 int got;
34 socklen_t sz = sizeof(peer_);
35
36 // RAII for the sd_
37 if ((sd_ = ::accept(sd, (struct sockaddr*)&peer_, &sz)) < 0)
38 throw(rogue::GeneralError::create("XvcConnection::XvcConnection()", "Unable to accept connection"));
39
40 // XVC protocol is synchronous / not pipelined :-(
41 // use TCP_NODELAY to make sure our messages (many of which
42 // are small) are sent ASAP
43 got = 1;
44 if (setsockopt(sd_, IPPROTO_TCP, TCP_NODELAY, &got, sizeof(got)))
45 throw(rogue::GeneralError::create("XvcConnection::XvcConnection()", "Unable to get TCP_NODELAY"));
46}
47
48rpx::XvcConnection::~XvcConnection() {
49 ::close(sd_);
50}
51
52ssize_t rpx::XvcConnection::readTo(void* buf, size_t count) {
53 fd_set rset;
54 int maxFd;
55 int nready;
56 struct timeval timeout;
57
58 FD_ZERO(&rset);
59 FD_SET(sd_, &rset);
60
61 // 1 Second Timeout
62 timeout.tv_sec = 1;
63 timeout.tv_usec = 0;
64
65 nready = ::select(sd_ + 1, &rset, NULL, NULL, &timeout);
66
67 if (nready > 0 && FD_ISSET(sd_, &rset))
68 return ::read(sd_, buf, count);
69 else
70 return 0;
71}
72
73// fill rx buffer to 'n' octets
74void rpx::XvcConnection::fill(uint64_t n) {
75 uint8_t* p = rp_ + rl_;
76 int got;
77 uint64_t k = n;
78
79 if (n <= rl_) return;
80
81 k -= rl_;
82 while (k > 0) {
83 got = readTo(p, k);
84
85 if (got <= 0) throw(rogue::GeneralError::create("XvcConnection::fill()", "Unable to read from socket"));
86
87 k -= got;
88 p += got;
89 }
90 rl_ = n;
91}
92
93// mark 'n' octets as 'consumed'
94void rpx::XvcConnection::bump(uint64_t n) {
95 rp_ += n;
96 rl_ -= n;
97 if (rl_ == 0) {
98 rp_ = &rxb_[0];
99 }
100}
101
102void rpx::XvcConnection::allocBufs() {
103 uint64_t tgtVecLen;
104 uint64_t overhead = 128; // headers and such;
105
106 // Determine the vector size supported by the target
107 tgtVecLen = drv_->query();
108
109 if (0 == tgtVecLen) {
110 // target can stream
111 tgtVecLen = maxVecLen_;
112 }
113
114 // What can the driver support?
115 supVecLen_ = drv_->getMaxVectorSize();
116
117 if (supVecLen_ == 0) {
118 // supports any size
119 supVecLen_ = tgtVecLen;
120 } else if (tgtVecLen < supVecLen_) {
121 supVecLen_ = tgtVecLen;
122 }
123
124 chunk_ = (2 * maxVecLen_ + overhead);
125
126 rxb_.resize(2 * chunk_);
127 txb_.resize(maxVecLen_ + overhead);
128
129 rp_ = &rxb_[0];
130 rl_ = 0;
131 tl_ = 0;
132}
133
134void rpx::XvcConnection::flush() {
135 int put;
136 uint8_t* p = &txb_[0];
137
138 while (tl_ > 0) {
139 put = write(sd_, p, tl_);
140
141 if (put <= 0) throw(rogue::GeneralError::create("XvcConnection::flush()", "Unable to send from socket"));
142
143 p += put;
144 tl_ -= put;
145 }
146}
147
148void rpx::XvcConnection::run() {
149 int got;
150 uint32_t bits, bitsLeft, bitsSent;
151 uint64_t bytes;
152 uint64_t vecLen;
153 uint64_t off;
154
155 allocBufs();
156
157 while (!drv_->isDone()) {
158 // read stuff;
159 got = readTo(rp_, chunk_);
160
161 if (got <= 0) throw(rogue::GeneralError::create("XvcConnection::run()", "Unable to read from socket"));
162
163 rl_ = got;
164
165 do {
166 fill(2);
167
168 if (0 == ::memcmp(rp_, "ge", 2)) {
169 fill(8);
170
171 drv_->query(); // informs the driver that there is a new connection
172
173 tl_ = snprintf(
174 reinterpret_cast<char*>(&txb_[0]), txb_.size(), "xvcServer_v1.0:%" PRIu64 "\n", maxVecLen_);
175
176 bump(8);
177 } else if (0 == ::memcmp(rp_, "se", 2)) {
178 uint32_t requestedPeriod;
179 uint32_t newPeriod;
180
181 fill(11);
182
183 requestedPeriod = (rp_[10] << 24) | (rp_[9] << 16) | (rp_[8] << 8) | rp_[7];
184
185 newPeriod = drv_->setPeriodNs(requestedPeriod);
186
187 for (unsigned u = 0; u < sizeof(newPeriod); u++) {
188 txb_[u] = (uint8_t)newPeriod;
189 newPeriod = newPeriod >> 8;
190 }
191
192 tl_ = 4;
193
194 bump(11);
195 } else if (0 == ::memcmp(rp_, "sh", 2)) {
196 fill(10);
197
198 bits = 0;
199 for (got = 9; got >= 6; got--) {
200 bits = (bits << 8) | rp_[got];
201 }
202 bytes = (bits + 7) / 8;
203
204 if (bytes > maxVecLen_)
205 throw(rogue::GeneralError::create("XvcConnection::run()", "Requested bit vector length too big"));
206
207 bump(10);
208 fill(2 * bytes);
209
210 vecLen = bytes > supVecLen_ ? supVecLen_ : bytes;
211
212 // break into chunks the driver can handle; due to the xvc layout we can't efficiently
213 // start working on a chunk while still waiting for more data to come in (well - we could
214 // but had to have the full TDI vector plus a chunk of the TMS vector in. Thus, we don't
215 // bother...).
216 for (off = 0, bitsLeft = bits; bitsLeft > 0; bitsLeft -= bitsSent, off += vecLen) {
217 bitsSent = 8 * vecLen;
218 if (bitsLeft < bitsSent) {
219 bitsSent = bitsLeft;
220 }
221
222 drv_->sendVectors(bitsSent, rp_ + off, rp_ + bytes + off, &txb_[0] + off);
223 }
224 tl_ = bytes;
225
226 bump(2 * bytes);
227 } else {
228 throw(rogue::GeneralError::create("XvcConnection::run()", "Unsupported message received"));
229 }
230 flush();
231
232 /* Repeat until all the characters from the first chunk are exhausted* (most likely the chunk just contained
233 * a vector shift message) and (most likely the chunk just contained a vector shift message) and it is
234 * exhausted during the first iteration. If for some reason it is not then we use the spill-over area for a
235 * second iteration which should then terminate this while loop.
236 */
237 } while (rl_ > 0);
238 }
239}
static GeneralError create(std::string src, const char *fmt,...)
Creates a formatted error instance.
Base transport driver for the AxisToJtag firmware protocol.
Definition JtagDriver.h:68