source: flair-src/trunk/lib/FlairSensorActuator/src/TargetEthController.cpp@ 348

Last change on this file since 348 was 249, checked in by Bayard Gildas, 6 years ago

bug #36 solved

File size: 11.7 KB
RevLine 
[3]1// %flair:license{
[15]2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
[3]4// %flair:license}
5// created: 2015/03/30
6// filename: TargetEthController.cpp
7//
8// author: Gildas Bayard
9// Copyright Heudiasyc UMR UTC/CNRS 7253
10//
11// version: $Id: $
12//
13// purpose: class that gets remote controls through an ethernet connection.
[15]14// Typical use case: a remote control is plugged in a workstation
15// and sends remote control
[3]16// data to a distant target (this class) through Wifi//
17//
18/*********************************************************************/
19#include "TargetEthController.h"
20#include <Controller.h>
21#include <FrameworkManager.h>
22#include <TcpSocket.h>
[178]23#include <UdpSocket.h>
[3]24#include <cstring>
25#include <string>
[214]26#include <Matrix.h>
[3]27#include <stdexcept>
28
29using namespace flair::core;
30using namespace flair::gui;
31using std::string;
32
[15]33namespace flair {
34namespace sensor {
[3]35
[137]36TargetEthController::TargetEthController(string name, uint16_t _port,
[15]37 uint8_t priority)
[137]38 : TargetController(name, priority), listeningPort(_port),
[15]39 receiveCurrentPosition(0) {
40 const bool blocking = true;
41 listeningSocket =
[137]42 new TcpSocket(getFrameworkManager(), "TEC_listening_socket", blocking, blocking);
[15]43 dataSocket =
[178]44 new UdpSocket(getFrameworkManager(), "TEC_data_socket", _port + 1); // receiving side
[3]45}
46
47TargetEthController::~TargetEthController() {
[15]48 // We are (currently) the server side. We must ask the client side to initiate
49 // tcp connexion closing to avoid the server socket
50 // to get stuck in TIME_WAIT state
51 Message msg(32);
52 if (controlSocket) {
53 Message cancelAcquisition(sizeof(ControllerAction));
54 ControllerAction exit = ControllerAction::Exit;
55 memcpy(cancelAcquisition.buffer, &exit, sizeof(ControllerAction));
56 controlSocket->SendMessage(cancelAcquisition.buffer,
57 cancelAcquisition.bufferSize);
58 // We don't expect any more data from the client, we're just waiting for the
59 // socket to be closed by the client
60 controlSocket->RecvMessage(msg.buffer, msg.bufferSize);
[238]61 delete controlSocket;
[15]62 }
[3]63
[15]64 // TargetController calls TargetEthController methods in its run
65 // we must stop the thread now
66 SafeStop();
67 Join();
[238]68 delete dataSocket;
69 delete listeningSocket;
[3]70}
71
72bool TargetEthController::IsConnected() const {
[15]73 // TODO
[3]74}
75
[15]76bool TargetEthController::IsDataFrameReady() {
77 // read up to the last data
78 ssize_t received;
79 size_t bytesToReceive = dataFrameSize - receiveCurrentPosition;
80 bool fullDatagramReceived = false;
[3]81
[38]82 do {
83 received=dataSocket->RecvMessage(receiveFrameBuffer+receiveCurrentPosition,bytesToReceive,TIME_NONBLOCK);
84 if (received>0) {
85 receiveCurrentPosition+=received;
86 bytesToReceive-=received;
87 if (bytesToReceive==0) {
88 //a full datagram has been read in receiveFrameBuffer
89 fullDatagramReceived=true;
90 //we swap the data and reception buffers to avoid copy
91 char *swapFrameBuffer=dataFrameBuffer;
92 dataFrameBuffer=receiveFrameBuffer;
93 receiveFrameBuffer=swapFrameBuffer;
94 receiveCurrentPosition=0;
95 bytesToReceive=dataFrameSize;
96 }
97 }
98 } while (!(received<0));
[3]99
[15]100 return fullDatagramReceived;
[3]101}
102
[15]103uint8_t TargetEthController::getByteOrNull(char *buffer, int byte,
104 size_t bufferSize) {
105 if (byte < bufferSize)
106 return buffer[byte];
107 else
108 return 0;
[3]109}
110
[15]111uint32_t TargetEthController::charBufferToUint32(char *buffer,
112 size_t bufferSize) {
113 union {
114 uint32_t int32;
115 char byte[4];
116 } bitField;
117 if (!IsBigEndian()) {
118 bitField.byte[0] = getByteOrNull(buffer, 3, bufferSize);
119 bitField.byte[1] = getByteOrNull(buffer, 2, bufferSize);
120 bitField.byte[2] = getByteOrNull(buffer, 1, bufferSize);
121 bitField.byte[3] = getByteOrNull(buffer, 0, bufferSize);
122 } else {
123 bitField.byte[0] = getByteOrNull(buffer, 0, bufferSize);
124 bitField.byte[1] = getByteOrNull(buffer, 1, bufferSize);
125 bitField.byte[2] = getByteOrNull(buffer, 2, bufferSize);
126 bitField.byte[3] = getByteOrNull(buffer, 3, bufferSize);
127 }
128 return bitField.int32;
[3]129}
130
[15]131// read _up_to_16_bits_ in a buffer
132uint16_t TargetEthController::readBits(uint8_t offsetInBits,
133 uint8_t valueSizeInBits, char *buffer,
134 size_t bufferSize) {
135 // parameters check
136 if (valueSizeInBits > 16)
137 throw std::range_error("bitfield should be at max 16bits wide");
138 size_t minBufferSize = (offsetInBits + valueSizeInBits) / 8;
139 if ((offsetInBits + valueSizeInBits) % 8 != 0)
140 minBufferSize++;
141 if (bufferSize < minBufferSize)
142 throw std::range_error("buffer too small");
143 // skip first bytes
144 size_t bytesToSkip = offsetInBits / 8;
145 buffer += bytesToSkip;
146 bufferSize -= bytesToSkip;
147 offsetInBits -= bytesToSkip * 8;
148 // take care of endianness
149 uint32_t value = charBufferToUint32(buffer, bufferSize);
150 value >>= 32 - offsetInBits - valueSizeInBits;
151 value &= (1 << valueSizeInBits) - 1;
152 return (uint16_t)value;
[3]153}
154
[214]155void TargetEthController::AcquireAxisData(core::Matrix &axis) {
[15]156 axis.GetMutex();
157 // char testFrameBuffer[3]={(char)0x09,(char)0x59,(char)0xB8};
158 for (unsigned int i = 0; i < axisNumber; i++) {
159 uint16_t rawAxisValue =
160 readBits(i * bitsPerAxis, bitsPerAxis, dataFrameBuffer, dataFrameSize);
161 // uint16_t
162 // rawAxisValue=readBits(i*bitsPerAxis,bitsPerAxis,testFrameBuffer);
163 uint16_t scale = 1 << (bitsPerAxis - 1);
164 // Thread::Info("RawAxisValue=%d, scale=%d => scaled rawValue=%d, float
165 // value)%f\n",rawAxisValue,scale,rawAxisValue-scale,(rawAxisValue-scale)/(float)scale);
166 axis.SetValueNoMutex(i, 0, (rawAxisValue - scale) / (float)scale);
167 }
168 axis.ReleaseMutex();
[3]169}
170
[214]171void TargetEthController::AcquireButtonData(core::Matrix &button) {
[15]172 uint8_t buttonValue;
173 int currentButton = 0;
174 button.GetMutex();
175 /*
176 for (unsigned int i=0;i<buttonNumber;i++) {
177 memcpy(&buttonValue,buttonOffset+i*sizeof(bool),sizeof(bool));
178 dataSocket->NetworkToHost((char*)&buttonValue,sizeof(bool));
179 button.SetValueNoMutex(i,0,buttonValue);
180// if (buttonValue) Thread::Info("Debug: button '%s' pressed\n",
181GetButtonName(i).c_str());
182 }*/
183 for (unsigned int i = 0; i < buttonNumber / 8; i++) {
184 memcpy(&buttonValue, dataFrameBuffer + buttonOffset + i * sizeof(uint8_t),
185 sizeof(uint8_t));
186 // dataSocket->NetworkToHost((char*)&buttonValue,sizeof(uint8_t));
187 for (unsigned int j = 0; j < 8; j++) {
188 button.SetValueNoMutex(currentButton, 0, (buttonValue >> j) & 0x01);
189 currentButton++;
[3]190 }
[15]191 }
192 button.ReleaseMutex();
[3]193}
194
[15]195string TargetEthController::GetAxisName(unsigned int axisId) const {
196 // TODO: should throw an exception if axisName==NULL or axisId>axisNumber
197 return axisName[axisId];
[3]198}
199
[15]200string TargetEthController::GetButtonName(unsigned int buttonId) const {
201 // TODO: should throw an exception if buttonName==NULL or
202 // buttonId>buttonNumber
203 return buttonName[buttonId];
[3]204}
205
206bool TargetEthController::ProcessMessage(Message *msg) {
[238]207 return !(controlSocket->SendMessage(msg->buffer, msg->bufferSize, TIME_INFINITE) < 0);
[3]208}
209
[15]210bool TargetEthController::IsControllerActionSupported(
211 ControllerAction action) const {
212 // TODO: here we should ask the remote side (host). Probably through the
213 // control socket
214 switch (action) {
215 case ControllerAction::SetLedOn:
216 return true;
217 case ControllerAction::SetLedOff:
218 return true;
219 case ControllerAction::Rumble:
220 return true;
221 case ControllerAction::FlashLed:
222 return true;
223 default:
224 return false;
225 }
[3]226}
227
228bool TargetEthController::ControllerInitialization() {
[15]229 char message[1024];
230 ssize_t received;
231 bool connected = false;
232 bool mustReadMore;
[3]233
[15]234 listeningSocket->Listen(listeningPort);
235 Thread::Info("Debug: Listening to port %d\n", listeningPort);
236 // accept incoming connection
[249]237 while (!controlSocket) {
[238]238 try {
239 controlSocket = listeningSocket->Accept(100000000);
240 } catch (std::logic_error &e) {
[249]241 Thread::Err("%s\n",e.what());
242 if (ToBeStopped())
243 return false;
[238]244 } catch (std::runtime_error e) {
245 // timeout
[249]246 //Thread::Err("%s\n",e.what());
[15]247 if (ToBeStopped())
248 return false;
[238]249 }
[15]250 }
251 Thread::Info("Debug: Connexion accepted\n");
[3]252
[15]253 // get axis stuff
254 bool axisNumberRead = false;
255 while (!axisNumberRead) {
256 try {
[238]257 axisNumber = controlSocket->ReadUInt32(100000000);
[15]258 // Thread::Info("Debug: axisNumber %d\n", axisNumber);
259 axisNumberRead = true;
260 } catch (std::runtime_error e) {
261 // timeout
262 if (ToBeStopped())
263 return false;
[3]264 }
[15]265 }
266 bool bitsPerAxisRead = false;
267 while (!bitsPerAxisRead) {
268 try {
[238]269 bitsPerAxis = controlSocket->ReadUInt32(100000000);
[15]270 // Thread::Info("Debug: bits per axis %d\n", bitsPerAxis);
271 bitsPerAxisRead = true;
272 } catch (std::runtime_error e) {
273 // timeout
274 if (ToBeStopped())
275 return false;
[3]276 }
[15]277 }
278 axisName = new string[axisNumber];
279 for (unsigned int i = 0; i < axisNumber; i++) {
280 // read string size
281 int stringSize;
282 bool stringSizeRead = false;
283 while (!stringSizeRead) {
284 try {
[238]285 stringSize = controlSocket->ReadUInt32(100000000);
[15]286 stringSizeRead = true;
287 } catch (std::runtime_error e) {
288 // timeout
289 if (ToBeStopped())
290 return false;
291 }
[3]292 }
[15]293 // read string
294 bool axisNameRead = false;
295 while (!axisNameRead) {
296 try {
[238]297 axisName[i] = controlSocket->ReadString(stringSize, 100000000);
[15]298 axisNameRead = true;
299 } catch (std::runtime_error e) {
300 // timeout
301 if (ToBeStopped())
302 return false;
303 }
304 }
305 // Thread::Info("Debug: axisName for axis %d %s\n", i, axisName[i].c_str());
306 }
[3]307
[15]308 // get button stuff
309 bool buttonNumberRead = false;
310 while (!buttonNumberRead) {
311 try {
[238]312 buttonNumber = controlSocket->ReadUInt32(100000000);
[15]313 buttonNumberRead = true;
314 } catch (std::runtime_error e) {
315 // timeout
316 if (ToBeStopped())
317 return false;
[3]318 }
[15]319 }
320 // Thread::Info("Debug: buttonNumber %d\n", buttonNumber);
321 buttonName = new string[buttonNumber];
322 for (unsigned int i = 0; i < buttonNumber; i++) {
323 // read string size
324 int stringSize;
325 bool stringSizeRead = false;
326 while (!stringSizeRead) {
327 try {
[238]328 stringSize = controlSocket->ReadUInt32(100000000);
[15]329 stringSizeRead = true;
330 } catch (std::runtime_error e) {
331 // timeout
332 if (ToBeStopped())
333 return false;
334 }
[3]335 }
[15]336 // read string
337 bool buttonNameRead = false;
338 while (!buttonNameRead) {
339 try {
[238]340 buttonName[i] = controlSocket->ReadString(stringSize, 10000000);
[15]341 buttonNameRead = true;
342 } catch (std::runtime_error e) {
343 // timeout
344 if (ToBeStopped())
345 return false;
346 }
347 }
348 // Thread::Info("Debug: buttonName for button %d %s\n", i,
349 // buttonName[i].c_str());
350 }
[3]351
[15]352 // dataFrameSize=axisNumber*sizeof(float)+buttonNumber/8*sizeof(uint8_t);
353 buttonOffset = (axisNumber * bitsPerAxis) / 8;
354 if ((axisNumber * bitsPerAxis) % 8 != 0)
355 buttonOffset++;
356 dataFrameSize = buttonOffset + (buttonNumber / 8) * sizeof(uint8_t);
357 if ((buttonNumber % 8) != 0)
358 dataFrameSize++;
359 dataFrameBuffer = new char[dataFrameSize];
360 receiveFrameBuffer = new char[dataFrameSize];
[3]361
[15]362 Thread::Info("Controller connected with host side\n");
363 if (buttonNumber % 8 != 0)
364 Thread::Err("Button number is not multiple of 8\n");
365 return true;
[3]366}
367
368} // end namespace sensor
369} // end namespace flair
Note: See TracBrowser for help on using the repository browser.