AnimatLab  2
Test
RbAnimatSerial.cpp
1 // RbAnimatSerial.cpp: implementation of the RbAnimatSerial class.
2 //
4 
5 #include "StdAfx.h"
6 #include <stdarg.h>
7 #include "RbMovableItem.h"
8 #include "RbBody.h"
9 #include "RbJoint.h"
10 #include "RbMotorizedJoint.h"
11 #include "RbHingeLimit.h"
12 #include "RbHinge.h"
13 #include "RbRigidBody.h"
14 #include "RbStructure.h"
15 #include "RbAnimatSerial.h"
16 
17 #define PACKET_INFO_SIZE 6 //Size of the header, packet size, message id, and checksum in bytes
18 #define START_MESSAGE_INFO_BYTE 5
19 #define HEADER_SIZE 5
20 #define DATA_SIZE 6
21 #define FOOTER_SIZE 1
22 
23 //Union to store bytes and float on top of each other
24 typedef union {
25  unsigned char b[4];
26  float f;
27 } bfloat;
28 
30 {
31  namespace Robotics
32  {
33  namespace RobotIOControls
34  {
35 
37 // Construction/Destruction
39 
40 RbAnimatSerial::RbAnimatSerial()
41 {
42  m_strPort = "";
43  m_iBaudRate = 38400;
44 
45  m_index = -1;
46  m_checksum = 0;
47  m_iMessageID = -1;
48  m_iPacketSize = 0;
49  m_bUseRemoteDataTypes = false;
50 
51  for(int iIndex=0; iIndex<MAX_ANIMAT_BUFFER; iIndex++)
52  m_vals[iIndex] = 0;
53 }
54 
55 RbAnimatSerial::~RbAnimatSerial()
56 {
57  try
58  {
59  }
60  catch(...)
61  {Std_TraceMsg(0, "Caught Error in desctructor of RbAnimatSerial\r\n", "", -1, false, true);}
62 }
63 
64 void RbAnimatSerial::Port(std::string strPort)
65 {
66  m_strPort = strPort;
67 }
68 
69 std::string RbAnimatSerial::Port() {return m_strPort;}
70 
71 void RbAnimatSerial::BaudRate(int iRate)
72 {
73  Std_IsAboveMin((int) 0, iRate, true, "BaudRate");
74  m_iBaudRate = iRate;
75 }
76 
77 int RbAnimatSerial::BaudRate() {return m_iBaudRate;}
78 
79 #pragma region DataAccesMethods
80 
81 bool RbAnimatSerial::SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError)
82 {
83  std::string strType = Std_CheckString(strDataType);
84 
85  if(AnimatSim::Robotics::RemoteControl::SetData(strDataType, strValue, false))
86  return true;
87 
88  if(strType == "PORT")
89  {
90  Port(strValue);
91  Initialize();
92  return true;
93  }
94  else if(strType == "BAUDRATE")
95  {
96  BaudRate((int) atoi(strValue.c_str()));
97  return true;
98  }
99 
100  //If it was not one of those above then we have a problem.
101  if(bThrowError)
102  THROW_PARAM_ERROR(Al_Err_lInvalidDataType, Al_Err_strInvalidDataType, "Data Type", strDataType);
103 
104  return false;
105 }
106 
107 void RbAnimatSerial::QueryProperties(CStdPtrArray<TypeProperty> &aryProperties)
108 {
110 
111  aryProperties.Add(new TypeProperty("Port", AnimatPropertyType::String, AnimatPropertyDirection::Set));
112  aryProperties.Add(new TypeProperty("BaudRate", AnimatPropertyType::Integer, AnimatPropertyDirection::Set));
113 }
114 
115 #pragma endregion
116 
119 {
120  // Open device. Do this before calling the Initialize on the parts so they can have communications.
121  if(m_bEnabled)
122  {
123  //If the thread is running already then shut it down.
124  if(m_bSetupComplete)
125  ShutdownIO();
126 
127  if(!Std_IsBlank(m_strPort))
128  {
129  if(OpenIO())
130  {
131  StartIOThread();
132 
133  int iCount = m_aryLinks.GetSize();
134  for(int iIndex=0; iIndex<iCount; iIndex++)
135  m_aryLinks[iIndex]->Initialize();
136 
137  ResetData();
138  }
139  }
140  }
141 }
142 
143 bool RbAnimatSerial::OpenIO()
144 {
145  bool bOpen = m_Port.setup(m_strPort, m_iBaudRate);
146 
147  if(!m_lpSim->InSimulation() && !bOpen)
148  THROW_PARAM_ERROR(Rb_Err_lFailedUartSBeeConnection, Rb_Err_strFailedUartSBeeConnection, "ComPort", m_strPort);
149 
150  return bOpen;
151 }
152 
153 void RbAnimatSerial::CloseIO()
154 {
155  m_Port.close();
156 }
157 
159 {
160  //If we have not opened the port yet give it another try.
161  if(!m_Port.isInitialized())
162  Initialize();
163 
164  //Clear out anything that happened the first time we got stuff.
165  m_Port.flush();
166 }
167 
168 void RbAnimatSerial::ResetData()
169 {
170  RemoteControl::ResetData();
171 
172  m_index = -1;
173  m_checksum = 0;
174  m_iMessageID = -1;
175  m_iPacketSize = 0;
176 }
177 
178 void RbAnimatSerial::WaitForThreadNotifyReady()
179 {
180  RobotIOControl::WaitForThreadNotifyReady();
181 
182  //Give it just a bit of time to start waiting if required.
183  boost::this_thread::sleep(boost::posix_time::microseconds(10000));
184 }
185 
186 void RbAnimatSerial::ReadData()
187 {
188  bool bFound = false;
189 
190  while(m_Port.available() > 0 && !bFound)
191  {
192  //Get first header byte
193  if(m_index == -1)
194  {
195  // looking for new packet
196  if(m_Port.readByte() == 0xff)
197  {
198  m_vals[0] = 0xff;
199  m_checksum = (int) m_vals[0];
200  m_index = 1;
201  m_iMessageID = -1;
202  m_iPacketSize = 0;
203  }
204  }
205  //Get second header byte
206  else if(m_index == 1)
207  {
208  m_vals[m_index] = (unsigned char) m_Port.readByte();
209  if(m_vals[m_index] == 0xff)
210  {
211  m_checksum += (int) m_vals[m_index];
212  m_index++;
213  }
214  else
215  m_index = -1; //Start over if the second byte is not 0xff
216  }
217  //Get the message ID
218  else if(m_index==2)
219  {
220  m_vals[m_index] = (unsigned char) m_Port.readByte();
221  m_iMessageID = m_vals[m_index];
222 
223  m_checksum += (int) m_vals[m_index];
224  m_index++;
225  }
226  //Get the message size byte 1
227  else if(m_index==3)
228  {
229  m_vals[m_index] = (unsigned char) m_Port.readByte();
230  m_iPacketSize = m_vals[m_index];
231 
232  m_checksum += (int) m_vals[m_index];
233  m_index++;
234  }
235  //Get the message size byte 2
236  else if(m_index==4)
237  {
238  m_vals[m_index] = (unsigned char) m_Port.readByte();
239  m_iPacketSize += (m_vals[m_index] << 8);
240 
241  //If the message size is greater than 128 then something is wrong. Start over.
242  if(m_iPacketSize > 128)
243  m_index = -1;
244  else
245  {
246  m_checksum += (int) m_vals[m_index];
247  m_index++;
248  }
249  }
250  else if(m_index > 4 && m_index <= m_iPacketSize)
251  {
252  m_vals[m_index] = (unsigned char) m_Port.readByte();
253 
254  if(m_index == (m_iPacketSize-1))
255  { // packet complete
256  //The transmitted checksum is the last entry
257  int iChecksum = m_vals[m_index];
258 
259  if(m_checksum%256 != iChecksum)
260  {
261  OutputDebugString("Checksum error. Writing Resend message.");
262  WriteResendData();
263  // packet error!
264  m_index = -1;
265  return; // 0
266  }
267  else
268  {
269  if(m_iMessageID == 2)
270  WriteAllData();
271  else if(m_iMessageID == 1)
272  {
273  int iStop = m_iPacketSize - 1; //Exclude the checksum at the end
274 
275  for(int iIdx=START_MESSAGE_INFO_BYTE; iIdx<iStop; iIdx+=DATA_SIZE)
276  {
277  m_id.bval[0] = m_vals[iIdx];
278  m_id.bval[1] = m_vals[iIdx+1];
279  m_value.bval[0] = m_vals[iIdx+2];
280  m_value.bval[1] = m_vals[iIdx+3];
281  m_value.bval[2] = m_vals[iIdx+4];
282  m_value.bval[3] = m_vals[iIdx+5];
283 
284  SetDataValue(m_id.ival, m_value.fval);
285  }
286  }
287  }
288 
289  m_index = -1;
290  m_Port.flush();
291  bFound = true;
292  }
293  else
294  {
295  m_checksum += (int) m_vals[m_index];
296  m_index++;
297  }
298 
299  if(m_index >= MAX_ANIMAT_BUFFER)
300  m_index = -1;
301  }
302 
303  }
304 }
305 
306 
307 void RbAnimatSerial::WriteData()
308 {
309  CStdArray<RemoteControlLinkage *> aryWrites;
310 
311  if(FindDataToWrite(aryWrites))
312  WriteData(aryWrites);
313 }
314 
315 void RbAnimatSerial::WriteData(CStdArray<RemoteControlLinkage *> &aryWrites)
316 {
317  int iCount = aryWrites.GetSize();
318  int checksum = 0xFF + 0xFF + 0x01;
319 
320  //First write the header
321  m_Port.writeByte((unsigned char) 0xFF);
322  m_Port.writeByte((unsigned char) 0xFF);
323  m_Port.writeByte((unsigned char) 0x01);
324 
325  m_size.ival = HEADER_SIZE + (DATA_SIZE * iCount) + FOOTER_SIZE;
326  m_Port.writeByte((unsigned char) m_size.bval[0]);
327  checksum += m_size.bval[0];
328  m_Port.writeByte((unsigned char) m_size.bval[1]);
329  checksum += m_size.bval[1];
330 
331  for(int i=0; i<iCount; i++)
332  {
333  m_id.ival = aryWrites[i]->m_Data.m_iButtonID;
334  m_value.fval = aryWrites[i]->m_Data.m_fltValue;
335  aryWrites[i]->AppliedValue(aryWrites[i]->m_Data.m_fltValue);
336 
337  m_Port.writeByte((unsigned char) m_id.bval[0]);
338  m_Port.writeByte((unsigned char) m_id.bval[1]);
339  m_Port.writeByte((unsigned char) m_value.bval[0]);
340  m_Port.writeByte((unsigned char) m_value.bval[1]);
341  m_Port.writeByte((unsigned char) m_value.bval[2]);
342  m_Port.writeByte((unsigned char) m_value.bval[3]);
343 
345  //std::string strDebug = "Val: " + STR((int) m_value.bval[0]) + ", " + STR((int) m_value.bval[1]) + ", " + STR((int) m_value.bval[2]) + ", " + STR((int) m_value.bval[3]) + "\r\n";
346  //OutputDebugString(strDebug.c_str());
347 
348  checksum += m_id.bval[0];
349  checksum += m_id.bval[1];
350  checksum += m_value.bval[0];
351  checksum += m_value.bval[1];
352  checksum += m_value.bval[2];
353  checksum += m_value.bval[3];
354  }
355 
356  unsigned char bchecksum = (unsigned char) (checksum%256);
357  m_Port.writeByte(bchecksum);
358 
360  //std::string strDebug = "Send Data ID: " + STR(m_id.ival) + ", Val: " + STR(m_value.fval) + "\r\n";
361  //OutputDebugString(strDebug.c_str());
362 }
363 
364 void RbAnimatSerial::WriteAllData()
365 {
366  CStdArray<RemoteControlLinkage *> aryWrites;
367 
368  int iCount = m_aryOutLinks.GetSize();
369  for(int i=0; i<iCount; i++)
370  aryWrites.Add(m_aryOutLinks[i]);
371 
372  WriteData(aryWrites);
373 }
374 
375 void RbAnimatSerial::WriteResendData()
376 {
377  int checksum = 0xFF + 0xFF + 0x02;
378 
379  //First write the header
380  m_Port.writeByte((unsigned char) 0xFF);
381  m_Port.writeByte((unsigned char) 0xFF);
382  m_Port.writeByte((unsigned char) 0x02);
383 
384  m_size.ival = HEADER_SIZE + FOOTER_SIZE;
385  m_Port.writeByte((unsigned char) m_size.bval[0]);
386  checksum += m_size.bval[0];
387  m_Port.writeByte((unsigned char) m_size.bval[1]);
388  checksum += m_size.bval[1];
389 
390  unsigned char bchecksum = (unsigned char) (checksum%256);
391  m_Port.writeByte(bchecksum);
392 
394  //std::string strDebug = "Send Data ID: " + STR(m_id.ival) + ", Val: " + STR(m_value.fval) + "\r\n";
395  //OutputDebugString(strDebug.c_str());
396 }
397 
399 {
400  if(!m_lpSim->Paused())
401  {
402  ReadData();
403  WriteData();
404  CheckStartedStopped();
406  }
407 }
408 
410 {
411  AnimatSim::Robotics::RemoteControl::Load(oXml);
412 
413  oXml.IntoElem();
414  Port(oXml.GetChildString("Port", m_strPort));
415  BaudRate(oXml.GetChildInt("BaudRate", m_iBaudRate));
416  oXml.OutOfElem();
417 }
418 
419 
420  } //RobotIOControls
421  } // Robotics
422 } //RoboticsAnimatSim
423 
CStdPtrArray< RemoteControlLinkage > m_aryLinks
Definition: RemoteControl.h:14
virtual bool InSimulation()
Used to determine if we are running in a simulation, or in a real control mode.
Definition: Simulator.cpp:1673
virtual bool SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError=true)
Set a variable based on a string data type name.
virtual bool SetData(const std::string &strDataType, const std::string &strValue, bool bThrowError=true)
Set a variable based on a string data type name.
virtual void Load(StdUtils::CStdXml &oXml)
Loads the item using an XML data packet.
virtual void Initialize()
We need to override this method because it does not care if it is in simulation mode or not...
virtual void StepIO()
This method is called from within the IO thread. It calls StepIO for each part.
CStdArray< RemoteControlLinkage * > m_aryOutLinks
Only the linkages that are outlinks.
Definition: RemoteControl.h:20
Simulator * m_lpSim
The pointer to a Simulation.
Definition: AnimatBase.h:43
virtual bool Paused()
Gets whether the Simulation is paused.
Definition: Simulator.cpp:347
virtual bool IntoElem()
Goes into the next element where the cursor is located.
Definition: StdXml.cpp:42
virtual void ShutdownIO()
This method is called just before the IO thread is closed down. It gives the IO objects a chance to d...
virtual void SimStarting()
Called just before the simulation starts.
virtual int GetChildInt(std::string strElementName)
Gets an integer value from the element with the specified name.
Definition: StdXml.cpp:456
bool Std_IsAboveMin(int iMinVal, int iVal, bool bThrowError, std::string strParamName, bool bInclusiveLimit)
Tests if a number is above a minimum value.
virtual void QueryProperties(CStdPtrArray< TypeProperty > &aryProperties)
Queries this object for a list of properties that can be changed using SetData.
Declares the vortex structure class.
Declares the vortex hinge class.
A standard xml manipulation class.
Definition: StdXml.h:19
virtual void StepIO()
This method is called from within the IO thread. It calls StepIO for each part.
virtual std::string GetChildString(std::string strElementName)
Gets a string value from the element with the specified name.
Definition: StdXml.cpp:307
void Std_TraceMsg(const int iLevel, std::string strMessage, std::string strSourceFile, int iSourceLine, bool bLogToFile, bool bPrintHeader)
Traces a message to the debugger window.
int m_iBaudRate
The baud rate of communications for this XBee.
bool m_bEnabled
Tells if this item is enabled or not. If it is not enabled then it is not run.
Definition: AnimatBase.h:40
std::string m_strPort
The serial port this Xbee communicates on.
virtual bool OutOfElem()
Goes out of the element where the cursor is located.
Definition: StdXml.cpp:56
bool Std_IsBlank(std::string strVal)
Trims a string and tests if a string is blank.
std::string Std_CheckString(std::string strVal)
Converts a string to upper case and trims it.
bool m_bSetupComplete
Set to true once the IO is setup correctly.
Classes for implementing the cm-labs vortex physics engine for AnimatLab.