Changeset 15 in flair-src for trunk/lib/FlairSensorActuator/src/HostEthController.cpp
- Timestamp:
- 04/08/16 15:40:57 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/FlairSensorActuator/src/HostEthController.cpp
r3 r15 11 11 // version: $Id: $ 12 12 // 13 // purpose: Base class for host side remote controls that talks to target side through ethernet connection 13 // purpose: Base class for host side remote controls that talks to target 14 // side through ethernet connection 14 15 // 15 16 // … … 37 38 using std::string; 38 39 39 namespace flair 40 { 41 namespace sensor 42 { 43 44 HostEthController::HostEthController(const FrameworkManager* parent,string name,string _address,int _port,uint32_t period,uint32_t _bitsPerAxis,uint8_t priority) : 45 Thread(parent,name,priority),IODevice(parent,name),tab(new Tab(parent->GetTabWidget(),name)),axisNumber(0),buttonNumber(0),targetAddress(_address),targetPort(_port), 46 bitsPerAxis(_bitsPerAxis),dataFrameBuffer(NULL),meaningfulDataAvailable(false) { 47 tabWidget=new TabWidget(tab->NewRow(),name); 48 49 const bool blocking=true; 50 controlSocket=new TcpSocket((Thread*)this,"eth controller control socket", blocking, !blocking); 51 dataSocket=new Socket((Thread*)this,"eth controller data socket",_address+":"+std::to_string(_port+1)); 52 dataSender=new DataSender((Thread*)this, this, "eth controller data sender thread"); 53 dataSender->SetPeriodMS(period); 54 dataSender->Start(); 55 56 //test binary 57 /* 58 uint16_t testValue=0b0111011010; //0x1DA 59 char buffer[3]={(char)0b10101011, (char)0b01100101, (char)0b10110110}; // 0xAB65B6 60 writeBits(testValue,10,buffer,7); // 0b1010101 0 11101101 0 0110110 0xAAED36 61 Thread::Info("Debug: buffer after bits written=%X %X\n",buffer[0],buffer[1]); 62 */ 63 connectionEstablishedMutex=new Mutex((Thread*)this); 40 namespace flair { 41 namespace sensor { 42 43 HostEthController::HostEthController(const FrameworkManager *parent, 44 string name, string _address, int _port, 45 uint32_t period, uint32_t _bitsPerAxis, 46 uint8_t priority) 47 : Thread(parent, name, priority), IODevice(parent, name), 48 tab(new Tab(parent->GetTabWidget(), name)), axisNumber(0), 49 buttonNumber(0), targetAddress(_address), targetPort(_port), 50 bitsPerAxis(_bitsPerAxis), dataFrameBuffer(NULL), 51 meaningfulDataAvailable(false) { 52 tabWidget = new TabWidget(tab->NewRow(), name); 53 54 const bool blocking = true; 55 controlSocket = new TcpSocket((Thread *)this, "eth controller control socket", 56 blocking, !blocking); 57 dataSocket = new Socket((Thread *)this, "eth controller data socket", 58 _address + ":" + std::to_string(_port + 1)); 59 dataSender = 60 new DataSender((Thread *)this, this, "eth controller data sender thread"); 61 dataSender->SetPeriodMS(period); 62 dataSender->Start(); 63 64 // test binary 65 /* 66 uint16_t testValue=0b0111011010; //0x1DA 67 char buffer[3]={(char)0b10101011, (char)0b01100101, (char)0b10110110}; // 68 0xAB65B6 69 writeBits(testValue,10,buffer,7); // 0b1010101 0 11101101 0 0110110 0xAAED36 70 Thread::Info("Debug: buffer after bits written=%X %X\n",buffer[0],buffer[1]); 71 */ 72 connectionEstablishedMutex = new Mutex((Thread *)this); 64 73 } 65 74 66 75 HostEthController::~HostEthController() { 76 SafeStop(); 77 Join(); 78 79 if (!getFrameworkManager()->ConnectionLost()) 80 delete tab; 81 } 82 83 void HostEthController::DrawUserInterface() { 84 Tab *plotTab = new Tab(tabWidget, "Measures"); 85 axisPlot = new DataPlot1D *[axisNumber]; 86 for (unsigned int i = 0; i < axisNumber; i++) { 87 // Start a new row or add up to the current row? We try to keep a 4/3 ratio 88 unsigned int columns = sqrt(4.0 * axisNumber / 3.0); 89 LayoutPosition *position; 90 if (i % columns == 0) { 91 position = plotTab->NewRow(); 92 } else { 93 position = plotTab->LastRowLastCol(); 94 } 95 axisPlot[i] = new DataPlot1D(position, axis->Name(i, 0), 96 -(1 << (nativeBitsPerAxis - 1)) * 1.2, 97 (1 << (nativeBitsPerAxis - 1)) * 1.5); 98 axisPlot[i]->AddCurve(axis->Element(i)); 99 } 100 // we don't plot the button state for now 101 } 102 103 string HostEthController::GetAxisDescription(unsigned int axis) { 104 return string("axis") + std::to_string(axis); 105 } 106 107 string HostEthController::GetButtonDescription(unsigned int button) { 108 return string("button") + std::to_string(button); 109 } 110 111 bool HostEthController::ControllerInitialization() { 112 113 buttonOffset = (axisNumber * bitsPerAxis) / 8; 114 if ((axisNumber * bitsPerAxis) % 8 != 0) 115 buttonOffset++; 116 dataFrameSize = buttonOffset + (buttonNumber / 8) * sizeof(uint8_t); 117 if ((buttonNumber % 8) != 0) 118 dataFrameSize++; 119 dataFrameBuffer = new char[dataFrameSize]; 120 return true; 121 } 122 123 void HostEthController::SendControllerInfo() { 124 // send axis info 125 controlSocket->WriteUInt32((uint32_t)axisNumber, 0); 126 controlSocket->WriteUInt32(bitsPerAxis, 0); 127 for (unsigned int i = 0; i < axisNumber; i++) { 128 // Thread::Info("Debug: sending axis name for axis %d = %s (takes up %d 129 // bytes)\n",i,GetAxisDescription(i).c_str(),GetAxisDescription(i).length()); 130 int stringLength = GetAxisDescription(i).length(); 131 controlSocket->WriteUInt32((uint32_t)stringLength, 0); 132 controlSocket->SendMessage(GetAxisDescription(i).c_str(), stringLength, 0); 133 } 134 135 // send button info 136 controlSocket->WriteUInt32((uint32_t)buttonNumber, 0); 137 for (unsigned int i = 0; i < buttonNumber; i++) { 138 int stringLength = GetButtonDescription(i).length(); 139 controlSocket->WriteUInt32((uint32_t)stringLength, 0); 140 controlSocket->SendMessage(GetButtonDescription(i).c_str(), stringLength, 141 0); 142 } 143 } 144 145 bool HostEthController::ConnectedWithTarget() { 146 char message[1024]; 147 ssize_t sent, received; 148 static bool connectionEstablished = false; 149 150 connectionEstablishedMutex->GetMutex(); 151 if (!connectionEstablished && 152 controlSocket->Connect(targetPort, targetAddress, 10)) { 153 Thread::Info("Connected to %s:%d\n", targetAddress.c_str(), targetPort); 154 SendControllerInfo(); 155 connectionEstablished = true; 156 } 157 connectionEstablishedMutex->ReleaseMutex(); 158 return connectionEstablished; 159 } 160 161 void HostEthController::Run() { 162 static int divider = 0; 163 Message *msgControllerAction = new Message(1024); 164 if (getFrameworkManager()->ErrorOccured() || !ControllerInitialization()) { 67 165 SafeStop(); 68 Join(); 69 70 if(!getFrameworkManager()->ConnectionLost()) delete tab; 71 } 72 73 void HostEthController::DrawUserInterface() { 74 Tab* plotTab=new Tab(tabWidget,"Measures"); 75 axisPlot=new DataPlot1D *[axisNumber]; 76 for (unsigned int i=0; i<axisNumber;i++) { 77 //Start a new row or add up to the current row? We try to keep a 4/3 ratio 78 unsigned int columns=sqrt(4.0*axisNumber/3.0); 79 LayoutPosition *position; 80 if (i%columns==0) { 81 position=plotTab->NewRow(); 82 } else { 83 position=plotTab->LastRowLastCol(); 166 Thread::Err("Une erreur a eu lieu, on ne lance pas la boucle\n"); 167 } 168 169 if (buttonNumber % 8 != 0) { 170 SafeStop(); 171 Thread::Err("Button number is not multiple of 8\n"); 172 } 173 174 while (!ToBeStopped()) { 175 // Thread::Info("Debug: entering acquisition loop\n"); 176 if (getFrameworkManager()->ConnectionLost() == true) 177 SafeStop(); 178 179 if (IsDataFrameReady()) { // wait for next data frame 180 meaningfulDataAvailable = true; 181 GetAxisData(); 182 GetButtonData(); 183 184 if (ConnectedWithTarget()) { 185 // read for commands from the target (remote control state change 186 // requests such as rumble or led on/off) 187 ssize_t bytesReceived = 188 controlSocket->RecvMessage((char *)msgControllerAction->buffer, 189 msgControllerAction->bufferSize); 190 if (bytesReceived > 0) { 191 // if the message is a cnx exit request we manage it here, if not it 192 // will be managed by the derived class 193 ControllerAction action; 194 memcpy(&action, msgControllerAction->buffer, 195 sizeof(ControllerAction)); 196 if (action == ControllerAction::Exit) { 197 // Thread::Info("Debug: exit request received from server\n"); 198 SafeStop(); 199 } 200 ProcessMessage(msgControllerAction); 84 201 } 85 axisPlot[i]=new DataPlot1D(position,axis->Name(i,0),-(1<<(nativeBitsPerAxis-1))*1.2,(1<<(nativeBitsPerAxis-1))*1.5); 86 axisPlot[i]->AddCurve(axis->Element(i)); 87 } 88 //we don't plot the button state for now 89 } 90 91 string HostEthController::GetAxisDescription(unsigned int axis) { 92 return string("axis")+std::to_string(axis); 93 } 94 95 string HostEthController::GetButtonDescription(unsigned int button) { 96 return string("button")+std::to_string(button); 97 } 98 99 bool HostEthController::ControllerInitialization() { 100 101 buttonOffset=(axisNumber*bitsPerAxis)/8; 102 if ((axisNumber*bitsPerAxis)%8!=0) buttonOffset++; 103 dataFrameSize=buttonOffset+(buttonNumber/8)*sizeof(uint8_t); 104 if ((buttonNumber%8)!=0) dataFrameSize++; 105 dataFrameBuffer=new char[dataFrameSize]; 106 return true; 107 } 108 109 void HostEthController::SendControllerInfo() { 110 //send axis info 111 controlSocket->WriteUInt32((uint32_t)axisNumber,0); 112 controlSocket->WriteUInt32(bitsPerAxis,0); 113 for (unsigned int i=0; i<axisNumber; i++) { 114 //Thread::Info("Debug: sending axis name for axis %d = %s (takes up %d bytes)\n",i,GetAxisDescription(i).c_str(),GetAxisDescription(i).length()); 115 int stringLength=GetAxisDescription(i).length(); 116 controlSocket->WriteUInt32((uint32_t)stringLength,0); 117 controlSocket->SendMessage(GetAxisDescription(i).c_str(), stringLength,0); 118 } 119 120 //send button info 121 controlSocket->WriteUInt32((uint32_t)buttonNumber,0); 122 for (unsigned int i=0; i<buttonNumber; i++) { 123 int stringLength=GetButtonDescription(i).length(); 124 controlSocket->WriteUInt32((uint32_t)stringLength,0); 125 controlSocket->SendMessage(GetButtonDescription(i).c_str(), stringLength,0); 126 } 127 } 128 129 bool HostEthController::ConnectedWithTarget() { 130 char message[1024]; 131 ssize_t sent,received; 132 static bool connectionEstablished=false; 133 134 connectionEstablishedMutex->GetMutex(); 135 if (!connectionEstablished && controlSocket->Connect(targetPort,targetAddress,10)) { 136 Thread::Info("Connected to %s:%d\n", targetAddress.c_str(), targetPort); 137 SendControllerInfo(); 138 connectionEstablished=true; 139 } 140 connectionEstablishedMutex->ReleaseMutex(); 141 return connectionEstablished; 142 } 143 144 void HostEthController::Run() { 145 static int divider=0; 146 Message *msgControllerAction=new Message(1024); 147 if(getFrameworkManager()->ErrorOccured()||!ControllerInitialization()) { 148 SafeStop(); 149 Thread::Err("Une erreur a eu lieu, on ne lance pas la boucle\n"); 150 } 151 152 if(buttonNumber%8!=0) { 153 SafeStop(); 154 Thread::Err("Button number is not multiple of 8\n"); 155 } 156 157 while(!ToBeStopped()) { 158 //Thread::Info("Debug: entering acquisition loop\n"); 159 if(getFrameworkManager()->ConnectionLost()==true) SafeStop(); 160 161 if (IsDataFrameReady()) { //wait for next data frame 162 meaningfulDataAvailable=true; 163 GetAxisData(); 164 GetButtonData(); 165 166 if (ConnectedWithTarget()) { 167 //read for commands from the target (remote control state change requests such as rumble or led on/off) 168 ssize_t bytesReceived=controlSocket->RecvMessage((char*)msgControllerAction->buffer,msgControllerAction->bufferSize); 169 if(bytesReceived>0) { 170 //if the message is a cnx exit request we manage it here, if not it will be managed by the derived class 171 ControllerAction action; 172 memcpy(&action,msgControllerAction->buffer,sizeof(ControllerAction)); 173 if (action==ControllerAction::Exit) { 174 //Thread::Info("Debug: exit request received from server\n"); 175 SafeStop(); 176 } 177 ProcessMessage(msgControllerAction); 178 } 179 } 180 } else {//try to connect even if host is not sending anything 181 ConnectedWithTarget(); 182 } 183 //Thread::Info("Debug: exiting acquisition loop\n"); 184 } 185 } 186 187 bool HostEthController::writeBits(uint16_t value,uint8_t valueSizeInBits,char *buffer,uint8_t offsetInBits) { 188 if (valueSizeInBits>16) return false; 189 uint8_t remainingBitsToWrite=valueSizeInBits; 190 //skip first bytes 191 buffer+=offsetInBits/8; 192 offsetInBits-=(offsetInBits/8)*8; 193 while (remainingBitsToWrite>0) { 194 uint8_t remainingBitsInByteBeforeWrite=8-offsetInBits; 195 uint8_t bitsToWrite=remainingBitsToWrite<remainingBitsInByteBeforeWrite?remainingBitsToWrite:remainingBitsInByteBeforeWrite; 196 uint8_t remainingBitsInByteAfterWrite=remainingBitsInByteBeforeWrite-bitsToWrite; 197 //write in the current byte 198 uint8_t byteMask=((1<<bitsToWrite)-1)<<remainingBitsInByteAfterWrite; 199 (*buffer)&=~byteMask; 200 uint16_t valueMask=(1<<remainingBitsToWrite)-1; 201 (*buffer)|=((value&valueMask)>>(remainingBitsToWrite-bitsToWrite))<<remainingBitsInByteAfterWrite; 202 //update state 203 remainingBitsToWrite-=bitsToWrite; 204 offsetInBits=(offsetInBits+bitsToWrite)%8; 205 buffer++; 206 } 207 return true; 202 } 203 } else { // try to connect even if host is not sending anything 204 ConnectedWithTarget(); 205 } 206 // Thread::Info("Debug: exiting acquisition loop\n"); 207 } 208 } 209 210 bool HostEthController::writeBits(uint16_t value, uint8_t valueSizeInBits, 211 char *buffer, uint8_t offsetInBits) { 212 if (valueSizeInBits > 16) 213 return false; 214 uint8_t remainingBitsToWrite = valueSizeInBits; 215 // skip first bytes 216 buffer += offsetInBits / 8; 217 offsetInBits -= (offsetInBits / 8) * 8; 218 while (remainingBitsToWrite > 0) { 219 uint8_t remainingBitsInByteBeforeWrite = 8 - offsetInBits; 220 uint8_t bitsToWrite = remainingBitsToWrite < remainingBitsInByteBeforeWrite 221 ? remainingBitsToWrite 222 : remainingBitsInByteBeforeWrite; 223 uint8_t remainingBitsInByteAfterWrite = 224 remainingBitsInByteBeforeWrite - bitsToWrite; 225 // write in the current byte 226 uint8_t byteMask = ((1 << bitsToWrite) - 1) 227 << remainingBitsInByteAfterWrite; 228 (*buffer) &= ~byteMask; 229 uint16_t valueMask = (1 << remainingBitsToWrite) - 1; 230 (*buffer) |= ((value & valueMask) >> (remainingBitsToWrite - bitsToWrite)) 231 << remainingBitsInByteAfterWrite; 232 // update state 233 remainingBitsToWrite -= bitsToWrite; 234 offsetInBits = (offsetInBits + bitsToWrite) % 8; 235 buffer++; 236 } 237 return true; 208 238 } 209 239 210 240 void HostEthController::BuildDataFrame() { 211 //int16_t testValue[4]={-120,-43,27,98}; //0x 88 d5 1b 62 212 for (unsigned int i=0;i<axisNumber;i++) { 213 //We shift value to always be positive (so that division/multiplication by power of 2 can easily be done with bit shifts) 214 uint16_t shiftedNativeAxisValue=axis->Value(i,0)+(1<<(nativeBitsPerAxis-1)); 215 //int16_t nativeAxisValue=testValue[i]; 216 uint16_t scaledAxisValue; 217 if (bitsPerAxis>nativeBitsPerAxis) { 218 scaledAxisValue=shiftedNativeAxisValue<<(bitsPerAxis-nativeBitsPerAxis); 219 } else { 220 scaledAxisValue=shiftedNativeAxisValue>>(nativeBitsPerAxis-bitsPerAxis); 221 } 222 //Thread::Info("Debug: shiftedNativeAxisValue=%#x, scaled axis value=%#x\n",shiftedNativeAxisValue,scaledAxisValue); 223 unsigned int offsetInBits=i*bitsPerAxis; 224 writeBits(scaledAxisValue,bitsPerAxis,dataFrameBuffer,offsetInBits); 225 } 226 //Thread::Info("Buffer après: %x %x %x\n", dataFrameBuffer[0], dataFrameBuffer[1], dataFrameBuffer[2]); 227 228 int currentButton=0; 229 uint8_t buttonArray[buttonNumber/8]; 230 for (unsigned int i=0;i<buttonNumber/8;i++) { 231 buttonArray[i]=0; 232 for(unsigned int j=0;j<8;j++) { 233 bool buttonValue=button->Value(currentButton,0); 234 if(buttonValue) buttonArray[i]+=1<<j; 235 currentButton++; 236 } 237 238 dataSocket->HostToNetwork((char *)&buttonArray[i],sizeof(uint8_t)); 239 memcpy(dataFrameBuffer+buttonOffset+i*sizeof(uint8_t),&buttonArray[i],sizeof(uint8_t)); 240 } 241 } 242 243 HostEthController::DataSender::DataSender(Object *parent,HostEthController* _hostEthController,string name,uint8_t priority):Thread(parent,name,priority),hostEthController(_hostEthController) { 244 245 } 241 // int16_t testValue[4]={-120,-43,27,98}; //0x 88 d5 1b 62 242 for (unsigned int i = 0; i < axisNumber; i++) { 243 // We shift value to always be positive (so that division/multiplication by 244 // power of 2 can easily be done with bit shifts) 245 uint16_t shiftedNativeAxisValue = 246 axis->Value(i, 0) + (1 << (nativeBitsPerAxis - 1)); 247 // int16_t nativeAxisValue=testValue[i]; 248 uint16_t scaledAxisValue; 249 if (bitsPerAxis > nativeBitsPerAxis) { 250 scaledAxisValue = shiftedNativeAxisValue 251 << (bitsPerAxis - nativeBitsPerAxis); 252 } else { 253 scaledAxisValue = 254 shiftedNativeAxisValue >> (nativeBitsPerAxis - bitsPerAxis); 255 } 256 // Thread::Info("Debug: shiftedNativeAxisValue=%#x, scaled axis 257 // value=%#x\n",shiftedNativeAxisValue,scaledAxisValue); 258 unsigned int offsetInBits = i * bitsPerAxis; 259 writeBits(scaledAxisValue, bitsPerAxis, dataFrameBuffer, offsetInBits); 260 } 261 // Thread::Info("Buffer après: %x %x %x\n", dataFrameBuffer[0], 262 // dataFrameBuffer[1], dataFrameBuffer[2]); 263 264 int currentButton = 0; 265 uint8_t buttonArray[buttonNumber / 8]; 266 for (unsigned int i = 0; i < buttonNumber / 8; i++) { 267 buttonArray[i] = 0; 268 for (unsigned int j = 0; j < 8; j++) { 269 bool buttonValue = button->Value(currentButton, 0); 270 if (buttonValue) 271 buttonArray[i] += 1 << j; 272 currentButton++; 273 } 274 275 dataSocket->HostToNetwork((char *)&buttonArray[i], sizeof(uint8_t)); 276 memcpy(dataFrameBuffer + buttonOffset + i * sizeof(uint8_t), 277 &buttonArray[i], sizeof(uint8_t)); 278 } 279 } 280 281 HostEthController::DataSender::DataSender(Object *parent, 282 HostEthController *_hostEthController, 283 string name, uint8_t priority) 284 : Thread(parent, name, priority), hostEthController(_hostEthController) {} 246 285 247 286 void HostEthController::DataSender::Run() { 248 if(getFrameworkManager()->ErrorOccured()==true) { 249 SafeStop(); 250 } 251 252 while(!ToBeStopped()) { 253 WaitPeriod(); 254 if (hostEthController->meaningfulDataAvailable && hostEthController->ConnectedWithTarget()) { 255 //send the data 256 hostEthController->BuildDataFrame(); 257 hostEthController->dataSocket->SendMessage(hostEthController->dataFrameBuffer,hostEthController->dataFrameSize); 258 } 259 } 287 if (getFrameworkManager()->ErrorOccured() == true) { 288 SafeStop(); 289 } 290 291 while (!ToBeStopped()) { 292 WaitPeriod(); 293 if (hostEthController->meaningfulDataAvailable && 294 hostEthController->ConnectedWithTarget()) { 295 // send the data 296 hostEthController->BuildDataFrame(); 297 hostEthController->dataSocket->SendMessage( 298 hostEthController->dataFrameBuffer, hostEthController->dataFrameSize); 299 } 300 } 260 301 } 261 302
Note:
See TracChangeset
for help on using the changeset viewer.