The VisAO Camera
framegrabber39.cpp
Go to the documentation of this file.
1 /************************************************************
2 * framegrabber39.cpp
3 *
4 * Author: Jared R. Males (jrmales@email.arizona.edu)
5 *
6 * Definitions for a class to capture frames from the BCU39, using the ebtables ulog.
7 *
8 * Developed as part of the Magellan Adaptive Optics system.
9 ************************************************************/
10 
11 /** \file framegrabber39.cpp
12  * \author Jared R. Males
13  * \brief Definitions for a class to capture frames from the BCU39, using the ebtables ulog.
14  *
15  *
16 */
17 
18 #include "framegrabber39.h"
19 
20 #include "display"
21 
22 static struct sockaddr_nl sa_local;
23 
24 static struct sockaddr_nl sa_kernel;
25 
26 
27 namespace VisAO
28 {
29 
30 framegrabber39::framegrabber39(int argc, char **argv) throw (AOException) : framegrabber<unsigned char>(argc, argv)
31 {
32  init_framegrabber39();
33 }
34 
35 framegrabber39::framegrabber39(std::string name, const std::string &conffile) throw (AOException) : framegrabber<unsigned char>(name, conffile)
36 {
37  init_framegrabber39();
38 }
39 
40 struct lutentry
41 {
42  int order;
43  int value;
44 };
45 
46 bool complutentries(lutentry a, lutentry b)
47 {
48  return a.value < b.value;
49 }
50 
51 void framegrabber39::init_framegrabber39()
52 {
53  sa_local.nl_family = AF_NETLINK;
54  sa_local.nl_groups = 1;
55 
56  sa_kernel.nl_family = AF_NETLINK;
57  sa_kernel.nl_pid = 0;
58  sa_kernel.nl_groups = 1;
59 
60  pktcnt = 0;
61 
62  rcvbufsize = BUFLEN;
63 
64  frameSizeDw = 4812;
65 
66  std::vector<lutentry> le(6400);
67  for(int i=0;i<6400;i++)
68  {
69  le[i].order = i;
70  le[i].value = displayLUT[i];
71  }
72 
73  std::sort(le.begin(), le.end(), complutentries);
74 
75  bcuLUT.resize(6400);
76  for(int i=0;i<6400;i++) bcuLUT[i] = le[i].order;
77 
78 
79  //Init the status board
81  if(create_statusboard(sizeof(framegrabber39_status_board)) != 0)
82  {
84  _logger->log(Logger::LOG_LEV_ERROR, "Could not create status board.");
85  }
86  else
87  {
89  strncpy(bsb->appname, MyFullName().c_str(), 25);
90  bsb->max_update_interval = pause_time;
91  }
92 
93 
94  STOP_FRAMEGRABBER = 0; //Always start running!
95 
96 
97 }
98 
99 /* Get the next ebt_ulog packet, talk to the kernel if necessary */
100 ebt_ulog_packet_msg_t * framegrabber39::ulog_get_packet()
101 {
102  static struct nlmsghdr *nlh = NULL;
103  static int len, remain_len;
104  static int pkts_per_msg = 0;
105 
106  ebt_ulog_packet_msg_t *msg;
107 
108  socklen_t addrlen = sizeof(sa_kernel);
109 
110  if (!nlh)
111  {
112  //printf("1.0\n");
113  if (pkts_per_msg && DEBUG_QUEUE)
114  {
115  logss.str("");
116  logss << "PACKETS IN LAST MSG: " << pkts_per_msg;
117  log_msg(Logger::LOG_LEV_ERROR, logss.str());
118  //std::cerr << logss.str() << " (logged) \n";
119  }
120  pkts_per_msg = 0;
121  //printf("1.1\n");
122  len = recvfrom(sfd, buf, BUFLEN, 0, (struct sockaddr *)&sa_kernel, &addrlen);
123  //printf("1.2\n");
124  if (errno == EINTR)
125  return 0;
126  if (addrlen != sizeof(sa_kernel))
127  {
128  logss.str("");
129  logss << "addrlen" << addrlen << " != " << sizeof(sa_kernel);
130  log_msg(Logger::LOG_LEV_ERROR, logss.str());
131  //std::cerr << logss.str() << " (logged) \n";
132  return 0;
133  }
134  if (len == -1)
135  {
136  logss.str("");
137  logss << "recvmsg: " << strerror(errno);
138  log_msg(Logger::LOG_LEV_ERROR, logss.str());
139  //std::cerr << logss.str() << " (logged) \n";
140  return 0;
141  }
142  nlh = (struct nlmsghdr *)buf;
143  if (nlh->nlmsg_flags & MSG_TRUNC || len > BUFLEN)
144  {
145  logss.str("");
146  logss << "packet truncated";
147  log_msg(Logger::LOG_LEV_ERROR, logss.str());
148  //std::cerr << logss.str() << " (logged) \n";
149  //printf("Packet truncated");
150  return 0;
151  }
152  if (!NLMSG_OK(nlh, BUFLEN))
153  {
154  logss.str("");
155  logss << "Netlink message parse error: " << strerror(errno);
156  log_msg(Logger::LOG_LEV_ERROR, logss.str());
157  //std::cerr << logss.str() << " (logged) \n";
158  return NULL;
159  }
160  }
161 
162  msg = (ebt_ulog_packet_msg_t *) NLMSG_DATA(nlh);
163 
164  remain_len = (len - ((char *)nlh - buf));
165  if (nlh->nlmsg_flags & NLM_F_MULTI && nlh->nlmsg_type != NLMSG_DONE)
166  nlh = NLMSG_NEXT(nlh, remain_len);
167  else
168  nlh = NULL;
169 
170  pkts_per_msg++;
171  return msg;
172 }
173 
174 /* details of the BCU39 frame are contained in adopt/lib/bcu_diag.h*/
176 {
177  set_euid_called();
178 
179  sa_local.nl_pid = getpid();
180 
181  sa_local.nl_groups = sa_kernel.nl_groups = 1 << (30 - 1);
182 
183  sfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
184 
185  if (!sfd)
186  {
187  logss.str("");
188  logss << "socket: " << strerror(errno);
189  log_msg(Logger::LOG_LEV_ERROR, logss.str());
190  //std::cerr << logss.str() << " (logged) \n";
191  return stop_framegrabber();
192  }
193 
194  if (bind(sfd, (struct sockaddr *)(&sa_local), sizeof(sa_local)) == -1)
195  {
196  logss.str("");
197  logss << "bind: " << strerror(errno);
198  log_msg(Logger::LOG_LEV_ERROR, logss.str());
199  //std::cerr << logss.str() << " (logged) \n";
200  return stop_framegrabber();
201  }
202 
203  if(setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, sizeof(rcvbufsize)) < 0)
204  {
205  logss.str("");
206  logss << "setsockopt: " << strerror(errno);
207  log_msg(Logger::LOG_LEV_ERROR, logss.str());
208  //std::cerr << logss.str() << " (logged) \n";
209  return stop_framegrabber();
210  }
211 
212 
213  logss.str("");
214  logss << "framegrabber39 running.";
215  log_msg(Logger::LOG_LEV_INFO, logss.str());
216  //std::cerr << logss.str() << " (logged) \n";
217 
218  t0 = get_curr_time();
219  pktcnt = 0;
220  RUNNING = 1;
221 
222  DiagnosticUdpHeader * bcuhead;
223 
224  int curr_frameId = -1;
225  int last_packetId=-1;
226 
227  int curr_pixel = 0;
228  int curr_pixel_offset = 4*2;
229  char * bcudata;
230  uint8* cursor;
231 
232  _frameSizeBytes = frameSizeDw * _FRAME_HEADER_SIZE_DW;
233  _packetsPerFrame = _frameSizeBytes / Constants::MAX_TDP_PACKET_SIZE;
234  if(_frameSizeBytes % Constants::MAX_TDP_PACKET_SIZE)
235  {
236  _packetsPerFrame++;
237  }
238 
239  //std::cout << "Packets Per Frame: " << _packetsPerFrame << "\n";
240  while(!STOP_FRAMEGRABBER && !TimeToDie)
241  {
242  if (!(msg = ulog_get_packet()))
243  {
244  //printf("returned 0\n");
245  continue;
246  }
247 
248  if (msg->version != EBT_ULOG_VERSION)
249  {
250  printf("WRONG VERSION: %d INSTEAD OF %d\n",
251  msg->version, EBT_ULOG_VERSION);
252  continue;
253  }
254  //printf("PACKET NR: %d\n", ++pktcnt);
255  ++pktcnt;
256  iph = NULL;
257  curr_len = ETH_HLEN;
258 
259  if (msg->data_len < curr_len)
260  {
261  goto letscontinue;
262  }
263 
264 
265  ehdr = (struct ethhdr *)msg->data;
266  etype = getethertypebynumber(ntohs(ehdr->h_proto));
267 
268  if (ehdr->h_proto == htons(ETH_P_IP))
269  iph = (struct iphdr *)(((char *)ehdr) + curr_len);
270  if (!iph)
271  goto letscontinue;
272 
273  curr_len += sizeof(struct iphdr);
274  if (msg->data_len < curr_len || msg->data_len < (curr_len += iph->ihl * 4 - sizeof(struct iphdr)))
275  {
276  goto letscontinue;
277  }
278 
279  //length of ip header *4bytes per word, +8 bytes for UDP, +2bytes to align the BCU packet.
280  bcuhead = (DiagnosticUdpHeader *)((char *) iph + iph->ihl*4 + 10);
281  //length of the diagnostic header is 12 bytes
282  bcudata = (char *) ((char *)bcuhead + 12);
283 
284  if(bcuhead->frameId == curr_frameId && bcuhead->packetId == last_packetId + 1)
285  {
286  //std::cout << bcuhead->frameId << " " << bcuhead->packetId << " " << bcuhead->tot_len << "\n";
287  last_packetId = bcuhead->packetId;
288 
289  if(last_packetId == 0)
290  {
291  sim = sis.set_next_image(sizeof(slopecomp_diagframe_pixels_slopes), 1);
292  sim->depth = 8;
293  //sim->frameNo = frameNo;
294  gettimeofday(&tv, 0);
295  sim->frame_time = tv;
296  }
297 
298  cursor = ((uint8 *) bcudata + curr_pixel_offset);
299  /*while(curr_pixel < 6400 && ((char *) cursor - (char *)ehdr) < msg->data_len)
300  {
301  sim->imdata[bcuLUT[curr_pixel]] = *((short*) cursor);
302  cursor++;
303  curr_pixel++;
304  }*/
305 
306  while(((char *) cursor - (char *)ehdr) < msg->data_len)
307  {
308  sim->imdata[curr_pixel] = *((unsigned char*) cursor);
309  cursor++;
310  curr_pixel++;
311  }
312 
313  //curr_pixel_offset = 0;
314 
315  if(last_packetId == _packetsPerFrame-1)
316  {
317  last_packetId = -1;
318  curr_frameId++;
319  curr_pixel = 0;
320  curr_pixel_offset = 0;//4*2;
321 
322  sim->frameNo = *( (uint32*) sim->imdata);
323 
325  send_ping();
326  }
327  }
328  else
329  {
330  last_packetId = -1;
331  curr_frameId = bcuhead->frameId + 1;
332  }
333 
334 
335  letscontinue:
336  ;
337  }
338 
339  double t1 = get_curr_time();
340 
341  close(sfd);
342 
343  set_euid_real(); //Go back to regular privileges
344  logss.str("");
345  logss << pktcnt << " frames.";
346  log_msg(Logger::LOG_LEV_INFO, logss.str());
347  //std::cerr << logss.str() << " (logged) \n";
348 
349  //std::cout << ((double)pktcnt)/(t1-t0) << " packets/sec" << std::endl;
350  //std::cout << ((double)pktcnt)/(t1-t0)/_packetsPerFrame << " fps";
351 
352  return stop_framegrabber();
353 }
354 
356 {
357  RUNNING = 0;
358 
359  logss.str("");
360  logss << "framegrabber39 stopped.";
361  log_msg(Logger::LOG_LEV_INFO, logss.str());
362  //std::cerr << logss.str() << " (logged) \n";
363 
364  return 0;
365 }
366 
368 {
369  static int last_pktcnt = 0;
370  static double last_t0 = t0;
371  double t1;
373  {
375 
377 
378  fsb->running = RUNNING;
379  fsb->reconstructing = serverPingEnabled;
380  fsb->saving = writerPingEnabled;
381 
382  if(RUNNING)
383  {
384  t1 = get_curr_time();
385  fsb->fps = ((double)(pktcnt-last_pktcnt))/(t1-last_t0)/_packetsPerFrame;
386  last_pktcnt = pktcnt;
387  last_t0 = t1;
388  }
389  else fsb->fps = 0.;
390  }
391  return 0;
392 }//int framegrabber39::update_statusboard()
393 
394 } //namespace VisAO
395 
virtual int update_statusboard()
Update the status board.
double t0
Starting time of framegrabber loop.
void log_msg(int LogLevel, std::string lmsg)
Report an error. Also calls log_msg. Overloaded from VisAOApp_base.
int enable_next_image()
Increments last_image.
double get_curr_time(void)
Gets the current CLOCK_REALTIME time, returns it in seconds to double precision.
Definition: libvisaoc.c:40
sharedim_stack< unsigned char > sis
The shared memory ring buffer for image storage.
Definition: framegrabber.h:100
#define STATUS_framegrabber39
Shared memory key for the BCU39 framegrabber status board.
Definition: statusboard.h:51
std::ostringstream logss
Conveninence string stream for building log messages.
void * statusboard_shmemptr
The pointer to the shared memory block for the statusboard.
virtual int stop_framegrabber()
Override this: framegrabber clean up.
virtual int update_statusboard()
Update the status board.
sharedim< unsigned char > * sim
Pointer to a shared memory image.
Definition: framegrabber.h:101
sharedim< IMDATA_TYPE > * set_next_image(int nx, int ny)
Sets the next image, and returns a pointer to it, but does not increment last_image.
int writerPingEnabled
Send pings on frame ready when true.
Definition: framegrabber.h:109
key_t statusboard_shmemkey
The key used to lookup the shared memory.
int TimeToDie
Global set by SIGTERM.
int serverPingEnabled
Send pings on frame ready when true.
Definition: framegrabber.h:116
double pause_time
Time to pause during application main loop.
Definition: VisAOApp_base.h:84
int STOP_FRAMEGRABBER
If true, framegrabber stops at top of next loop.
Definition: framegrabber.h:119
int create_statusboard(size_t sz)
Creates and attaches to the statusboard shared memory.
int set_euid_called()
Changes the user id of the process to euid_called.
int send_ping()
Sends a ping to the waiting process (usuallly a framewriter).
virtual int start_framegrabber()
Override this: it is where your framegrabber should do all its work. Check for !STOP_FRAMEGRABBER and...
The namespace of VisAO software.
Declarations for a class to capture frames from the BCU39, using the ebtables ulog.
timeval tv
Convenience variable for filling in the frame time in the image header.
Definition: framegrabber.h:124
int set_euid_real()
Changes the user id fo the process to the real user id.
int RUNNING
Status of framegrabber.
Definition: framegrabber.h:120