Now you can download a copy of these docs so you can use them offline! Download now
PCVideoServer.cpp
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) FIRST 2008. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
5 /*----------------------------------------------------------------------------*/
6 
7 #include <vxWorks.h>
8 
9 #include "PCVideoServer.h"
10 
11 #include <errnoLib.h>
12 #include <hostLib.h>
13 #include <inetLib.h>
14 #include <sockLib.h>
15 #include <cstring>
16 
17 #include "NetworkCommunication/UsageReporting.h"
18 #include "Task.h"
19 #include "Timer.h"
20 #include "Vision/AxisCamera.h"
21 #include "WPIErrors.h"
22 
27 class ScopedSocket {
28 public:
29  ScopedSocket(int camSock)
30  : m_camSock(camSock)
31  {
32  }
33 
34  ~ScopedSocket() {
35  if (m_camSock != ERROR) {
36  close(m_camSock);
37  }
38  }
39  // Cast to int allows you to pass this to any function that
40  // takes the socket as an int.
41  operator int() const {
42  return m_camSock;
43  }
44 
45 private:
46  int m_camSock;
47 };
48 
49 //============================================================================
50 // PCVideoServer
51 //============================================================================
52 
57  : m_serverTask("PCVideoServer", (FUNCPTR)s_ServerTask)
58  , m_newImageSem (NULL)
59  , m_stopServer (false)
60 {
62  m_newImageSem = cam.GetNewImageSem();
63  if (!cam.StatusIsFatal())
64  {
65  StartServerTask();
66  }
67  else
68  {
69  CloneError(&cam);
70  }
71 }
72 
78 {
79  // Stop the images to PC server.
80  Stop();
81  // Clear the error so that you can use this object to make a connection to
82  // the VIDEO_TO_PC_PORT to stop the ImageToPCServer if it is waiting to
83  // accept connections from a PC.
84  ClearError();
85  // Open a socket.
86  int camSock = socket(AF_INET, SOCK_STREAM, 0);
87  if (camSock == ERROR)
88  {
89  wpi_setErrnoError();
90  return;
91  }
92  ScopedSocket scopedCamSock(camSock);
93  // If successful
94  if (!StatusIsFatal())
95  {
96  // Create a connection to the localhost.
97  struct sockaddr_in selfAddr;
98  int sockAddrSize = sizeof(selfAddr);
99  bzero ((char *) &selfAddr, sockAddrSize);
100  selfAddr.sin_family = AF_INET;
101  selfAddr.sin_len = (u_char) sockAddrSize;
102  selfAddr.sin_port = htons (VIDEO_TO_PC_PORT);
103 
104  if (( (int)(selfAddr.sin_addr.s_addr = inet_addr (const_cast<char*>("localhost")) ) != ERROR) ||
105  ( (int)(selfAddr.sin_addr.s_addr = hostGetByName (const_cast<char*>("localhost")) ) != ERROR))
106  {
107  struct timeval connectTimeout;
108  connectTimeout.tv_sec = 1;
109  connectTimeout.tv_usec = 0;
110  connectWithTimeout(camSock, (struct sockaddr *) &selfAddr, sockAddrSize, &connectTimeout);
111  }
112  }
113 }
114 
118 int PCVideoServer::StartServerTask()
119 {
120  if (StatusIsFatal())
121  {
122  return -1;
123  }
124  int id = 0;
125  m_stopServer = false;
126  // Check for prior copy of running task
127  int oldId = taskNameToId((char*)m_serverTask.GetName());
128  if(oldId != ERROR)
129  {
130  // TODO: Report error. You are in a bad state.
131  taskDelete(oldId);
132  }
133 
134  // spawn video server task
135  // this is done to ensure that the task is spawned with the
136  // floating point context save parameter.
137  bool started = m_serverTask.Start((int)this);
138 
139  id = m_serverTask.GetID();
140 
141  if (!started)
142  {
143  wpi_setWPIError(TaskError);
144  return id;
145  }
146  taskDelay(1);
147  return id;
148 }
149 
154 {
155  StartServerTask();
156 }
157 
162 {
163  m_stopServer = true;
164 }
165 
169 int PCVideoServer::s_ServerTask(PCVideoServer *thisPtr)
170 {
171  return thisPtr->ServerTask();
172 }
173 
179 int PCVideoServer::ServerTask()
180 {
181  /* Setup to PC sockets */
182  struct sockaddr_in serverAddr;
183  int sockAddrSize = sizeof(serverAddr);
184  int pcSock = ERROR;
185  bzero ((char *) &serverAddr, sockAddrSize);
186  serverAddr.sin_len = (u_char) sockAddrSize;
187  serverAddr.sin_family = AF_INET;
188  serverAddr.sin_port = htons (VIDEO_TO_PC_PORT);
189  serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
190 
191  int success;
192  while (true)
193  {
194  taskSafe();
195  // Create the socket.
196  if ((pcSock = socket (AF_INET, SOCK_STREAM, 0)) == ERROR)
197  {
198  wpi_setErrnoErrorWithContext("Failed to create the PCVideoServer socket");
199  continue;
200  }
201  // Set the TCP socket so that it can be reused if it is in the wait state.
202  int reuseAddr = 1;
203  setsockopt(pcSock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&reuseAddr), sizeof(reuseAddr));
204  // Bind socket to local address.
205  if (bind (pcSock, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR)
206  {
207  wpi_setErrnoErrorWithContext("Failed to bind the PCVideoServer port");
208  close (pcSock);
209  continue;
210  }
211  // Create queue for client connection requests.
212  if (listen (pcSock, 1) == ERROR)
213  {
214  wpi_setErrnoErrorWithContext("Failed to listen on the PCVideoServer port");
215  close (pcSock);
216  continue;
217  }
218 
219  struct sockaddr_in clientAddr;
220  int clientAddrSize;
221  int newPCSock = accept (pcSock, reinterpret_cast<sockaddr*>(&clientAddr), &clientAddrSize);
222  if (newPCSock == ERROR)
223  {
224  close(pcSock);
225  continue;
226  }
227  //TODO: check camera error
228 
229  // Report usage when there is actually a connection.
230  nUsageReporting::report(nUsageReporting::kResourceType_PCVideoServer, 0);
231 
232  int numBytes = 0;
233  int imageDataSize = 0;
234  char* imageData = NULL;
235 
236  while(!m_stopServer)
237  {
238  success = semTake(m_newImageSem, 1000);
239  if (success == ERROR)
240  {
241  // If the semTake timed out, there are no new images from the camera.
242  continue;
243  }
244  success = AxisCamera::GetInstance().CopyJPEG(&imageData, numBytes, imageDataSize);
245  if (!success)
246  {
247  // No point in running too fast -
248  Wait(1.0);
249  // If camera is not initialzed you will get failure and
250  // the timestamp is invalid. Reset this value and try again.
251  continue;
252  }
253 
254  // Write header to PC
255  static const char header[4]={1,0,0,0};
256  int headerSend = write(newPCSock, const_cast<char*>(header), 4);
257 
258  // Write image length to PC
259  int lengthSend = write(newPCSock, reinterpret_cast<char*>(&numBytes), 4);
260 
261  // Write image to PC
262  int sent = write (newPCSock, imageData, numBytes);
263 
264  // The PC probably closed connection. Get out of here
265  // and try listening again.
266  if (headerSend == ERROR || lengthSend == ERROR || sent == ERROR)
267  {
268  break;
269  }
270  }
271  // Clean up
272  delete [] imageData;
273  close (newPCSock);
274  newPCSock = ERROR;
275  close (pcSock);
276  pcSock = ERROR;
277  taskUnsafe();
278  Wait(0.1);
279  }
280  return (OK);
281 }
282 
int CopyJPEG(char **destImage, int &destImageSize, int &destImageBufferSize)
Definition: AxisCamera.cpp:172
bool Start(uint32_t arg0=0, uint32_t arg1=0, uint32_t arg2=0, uint32_t arg3=0, uint32_t arg4=0, uint32_t arg5=0, uint32_t arg6=0, uint32_t arg7=0, uint32_t arg8=0, uint32_t arg9=0)
Definition: Task.cpp:52
Implements an object that automatically does a close on a camera socket on destruction.
void Start()
Start sending images to the PC.
const char * GetName()
Definition: Task.cpp:166
~PCVideoServer()
Destructor. Stop serving images and destroy this class.
void Stop()
Stop sending images to the PC.
virtual void ClearError() const
Clear the current error information associated with this sensor.
Definition: ErrorBase.cpp:46
virtual bool StatusIsFatal() const
Check if the current error code represents a fatal error.
Definition: ErrorBase.cpp:178
int32_t GetID()
Definition: Task.cpp:175
static AxisCamera & GetInstance(const char *cameraIP=NULL)
Definition: AxisCamera.cpp:75
SEM_ID GetNewImageSem()
Definition: AxisCamera.cpp:113
PCVideoServer()
Constructor.

Generated on Sat Apr 26 2014 12:26:45 for WPILibC++ by doxygen 1.8.6