AJA NTV2 SDK  17.1.1.1245
NTV2 SDK 17.1.1.1245
ntv2mailbox.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
8 #include "ntv2mailbox.h"
9 #include "ntv2utils.h"
10 #include <string.h>
11 
12 #if defined(AJA_MAC)
13  #include <mach/mach_time.h>
14  #include <CoreServices/CoreServices.h>
15  static int64_t s_PerformanceFrequency;
16  static bool s_bPerformanceInit = false;
17 #endif
18 
19 
20 #if defined(MSWindows)
21  static LARGE_INTEGER s_PerformanceFrequency;
22  static bool s_bPerformanceInit = false;
23 #endif
24 
25 #if defined(AJALinux) || defined(AJA_LINUX)
26  #include <unistd.h>
27  #if (_POSIX_TIMERS > 0)
28  #ifdef _POSIX_MONOTONIC_CLOCK
29  #define AJA_USE_CLOCK_GETTIME
30  #else
31  #undef AJA_USE_CLOCK_GETTIME
32  #endif
33  #endif
34 
35  #ifdef AJA_USE_CLOCK_GETTIME
36  #include <time.h>
37  #else
38  // Use gettimeofday - this is not really desirable
39  #include <sys/time.h>
40  #endif
41 #endif
42 
43 
44 CNTV2MailBox::CNTV2MailBox(CNTV2Card & device) : mDevice( device )
45 {
46 
47  bOffset = SAREK_MAILBOX;
48 
49  memset(rxBuf,0,sizeof(rxBuf));
50  memset(txBuf,0,sizeof(txBuf));
51 
52  _seqNum = SEQNUM_MIN;
53 }
54 
56 {
57 }
58 
59 bool CNTV2MailBox::sendMsg(uint32_t timeout)
60 {
61  // assumes pointer to a buf longer than the string;
62  int byte_len = (int)strlen((char*)txBuf);
63  int word_len = ((byte_len + 4) - (byte_len %4))/4;
64 
65  // write message
66  bool rv = writeMB(0xffffffff); // SOM
67  if (!rv)
68  {
70  return false;
71  }
72  rv = writeMB(nextSeqNum()); // sequence number
73  if (!rv)
74  {
76  return false;
77  }
78  rv = writeMB(word_len); // write wordcount
79  if (!rv)
80  {
82  return false;
83  }
84 
85  uint32_t * pBuf = txBuf;
86  for (int i = 0; i < word_len; i++)
87  {
88  writeMB( *pBuf++); // write message
89  }
90 
91  return rcvMsg(timeout);
92 }
93 
94 bool CNTV2MailBox::sendMsg(char * msg, uint32_t timeout)
95 {
96  // make local safe copy
97  strncpy((char*)txBuf,msg,sizeof(txBuf));
98 
99  return sendMsg(timeout);
100 }
101 
102 bool CNTV2MailBox::rcvMsg(uint32_t timeout)
103 {
104  uint32_t * pBuf = (uint32_t*)rxBuf;
105  memset(rxBuf,0,sizeof(rxBuf));
106 
107  // drain until next message (valid SAOM and valid seqNum)
108  bool rv;
109  bool valid = false;
110  do
111  {
112  rv = waitSOM(timeout);
113  if (!rv)
114  {
116  return false;
117  }
118 
119  uint32_t seqNum;
120  rv = readMB(seqNum);
121  if (!rv)
122  {
124  return false;
125  }
126  if (seqNum == currentSeqNum())
127  {
128  valid = true;
129  }
130  } while (!valid);
131 
132  uint32_t count;
133  rv = readMB(count);
134  if (!rv)
135  {
137  return false;
138  }
139 
140  if (count > FIFO_SIZE)
141  {
143  return false;
144  }
145 
146  if (count == 0)
147  {
149  return false;
150  }
151 
152  for (uint32_t i=0; i<count; i++)
153  {
154  uint32_t val;
155  readMB(val);
156  *pBuf++ = val;
157  }
158  *pBuf = 0;
159 
160  return true;
161 }
162 
163 bool CNTV2MailBox::writeMB(uint32_t val, uint32_t timeout)
164 {
165  bool rv = waitTxReady(timeout);
166  if (rv)
167  {
168  mDevice.WriteRegister(bOffset + MB_tWRDATA,val);
169  }
170  return rv;
171 }
172 
173 bool CNTV2MailBox::readMB(uint32_t & val, uint32_t timeout)
174 {
175  bool rv = waitRxReady(timeout);
176  if (rv)
177  {
178  mDevice.ReadRegister(bOffset + MB_tRDDATA, val);
179  }
180  return rv;
181 }
182 
183 bool CNTV2MailBox::waitSOM(uint32_t timeout)
184 {
185  // this keeps draining until a SOM is read or a timeout
186  uint32_t SOM = 0;
187  while (SOM != 0xffffffff)
188  {
189  bool rv = readMB(SOM,timeout);
190  if (!rv)
191  {
192  return false;
193  }
194  }
195  return true;
196 }
197 
199 {
200  bool empty = getStatus() & MBS_RX_EMPTY;
201  return !empty;
202 }
203 
204 bool CNTV2MailBox::waitRxReady(uint32_t timeout)
205 {
206  startTimer();
207  while (!rxReady())
208  {
209  if (getElapsedTime() > timeout)
210  {
211  return false;
212  }
213  }
214  return true;
215 }
216 
217 bool CNTV2MailBox::waitTxReady(uint32_t timeout)
218 {
219  startTimer();
220  while (getStatus() & MBS_TX_FULL)
221  {
222  if (getElapsedTime() > timeout)
223  {
224  return false;
225  }
226  }
227  return true;
228 }
229 
231 {
232  uint32_t val;
233  mDevice.ReadRegister(bOffset + MB_tSTATUS, val);
234  return val;
235 }
236 
237 bool CNTV2MailBox::ReadChannelRegister (const ULWord inReg, ULWord & outValue, const ULWord inMask, const ULWord inShift)
238 {
239  NTV2RegInfo regInfo (inReg, 0, inMask, inShift);
240  bool rv = mDevice.BankSelectReadRegister (NTV2RegInfo (chanOffset, chanNumber), regInfo);
241  if (rv)
242  outValue = regInfo.registerValue;
243  return rv;
244 }
245 
247 {
248  return mDevice.BankSelectWriteRegister (NTV2RegInfo (chanOffset, chanNumber), NTV2RegInfo (reg, value, mask, shift));
249 }
250 
251 void CNTV2MailBox::SetChannel(ULWord channelOffset, ULWord channelNumber)
252 {
253  chanOffset = channelOffset;
254  chanNumber = channelNumber;
255 }
256 
257 void CNTV2MailBox::getError(std::string & error)
258 {
260  {
261  error = mIpInternalErrorString;
262  }
263  else
264  {
266  }
268 }
269 
271 {
272  // If no MB do nothing, this is for Cochrane
273  if (!(getFeatures() & SAREK_MB_PRESENT))
274  return true;
275 
276  int waitCount = 20;
277  while (waitCount--)
278  {
280  {
281  return true;
282  }
284  }
285 
286  // timeout
288  return false;
289 }
290 
292 {
293  // If no MB do nothing, this is for Cochrane
294  uint32_t features = getFeatures();
295  if (features & SAREK_MB_PRESENT)
296  {
298  }
299 }
300 
301 void CNTV2MailBox::getResponse(std::string & response)
302 {
303  response.assign((char*)rxBuf);
304 }
305 
306 void CNTV2MailBox::startTimer()
307 {
308  _startTime = getSystemMilliseconds();
309 }
310 
311 uint64_t CNTV2MailBox::getElapsedTime()
312 {
313  return (getSystemMilliseconds() - _startTime);
314 }
315 
316 int64_t CNTV2MailBox::getSystemCounter()
317 {
318 #if defined(MSWindows)
319  LARGE_INTEGER performanceCounter;
320 
321  performanceCounter.QuadPart = 0;
322  if (!QueryPerformanceCounter(&performanceCounter))
323  {
324  return 0;
325  }
326 
327  return (int64_t)performanceCounter.QuadPart;
328 #endif
329 
330 #if defined(AJA_MAC)
331  return (int64_t) mach_absolute_time();
332 #endif
333 
334 #if defined(AJALinux) || defined(AJA_LINUX)
335 #ifdef AJA_USE_CLOCK_GETTIME
336  struct timespec ts;
338  return (ts.tv_sec * ((int64_t)1000000)) + (ts.tv_nsec / (int64_t)1000);
339 #else
340  struct timeval tv;
341  struct timezone tz;
342 
343  gettimeofday( &tv, &tz );
344  return (int64_t)((int64_t)tv.tv_sec * (int64_t)1000000 + tv.tv_usec);
345 #endif
346 #endif
347 }
348 
349 
350 int64_t CNTV2MailBox::getSystemFrequency()
351 {
352 #if defined(MSWindows)
353  if (!s_bPerformanceInit)
354  {
355  QueryPerformanceFrequency(&s_PerformanceFrequency);
356  s_bPerformanceInit = true;
357  }
358 
359  return (int64_t)s_PerformanceFrequency.QuadPart;
360 #endif
361 
362 #if defined(AJA_MAC)
363  if (!s_bPerformanceInit)
364  {
365  // 1 billion ticks approximately equals 1 sec on a Mac
366  static mach_timebase_info_data_t sTimebaseInfo;
367  uint64_t ticks = 1000000000;
368 
369  if ( sTimebaseInfo.denom == 0 )
370  {
371  (void) mach_timebase_info(&sTimebaseInfo);
372  }
373 
374  // Do the maths. We hope that the multiplication doesn't
375  // overflow; the price you pay for working in fixed point.
376  int64_t nanoSeconds = ticks * sTimebaseInfo.numer / sTimebaseInfo.denom;
377 
378  // system frequency - ticks per second units
379  s_PerformanceFrequency = ticks * 1000000000 / nanoSeconds;
380  s_bPerformanceInit = true;
381  }
382 
383  return s_PerformanceFrequency;
384 #endif
385 
386 #if defined(AJALinux) || defined(AJA_LINUX)
387  return 1000000;
388 #endif
389 }
390 
391 uint64_t CNTV2MailBox::getSystemMilliseconds()
392 {
393  uint64_t ticks = getSystemCounter();
394  uint64_t ticksPerSecond = getSystemFrequency();
395  uint64_t ms = 0;
396  if (ticksPerSecond)
397  {
398  // floats are being used here to avoid the issue of overflow
399  // or inaccuracy when chosing where to apply the '1000' correction
400  ms = uint64_t((double(ticks) / double(ticksPerSecond)) * 1000.);
401  }
402  return ms;
403 }
404 
405 
407 {
408  uint32_t val;
410  return val;
411 }
412 
413 
SEQNUM_MIN
#define SEQNUM_MIN
Definition: ntv2mailbox.h:39
CNTV2MailBox::getFeatures
uint32_t getFeatures()
Definition: ntv2mailbox.cpp:406
kRegSarekFwCfg
#define kRegSarekFwCfg
Definition: ntv2registersmb.h:105
CNTV2MailBox::getStatus
uint32_t getStatus()
Definition: ntv2mailbox.cpp:230
CNTV2MailBox::readMB
bool readMB(uint32_t &val, uint32_t timeout=50)
Definition: ntv2mailbox.cpp:173
CNTV2MailBox::SetChannel
void SetChannel(ULWord channelOffset, ULWord channelNumber)
Definition: ntv2mailbox.cpp:251
CNTV2MailBox::mDevice
CNTV2Card & mDevice
Definition: ntv2mailbox.h:79
CNTV2Card::AcquireMailBoxLock
virtual bool AcquireMailBoxLock(void)
Definition: ntv2register.cpp:4488
CNTV2MacDriverInterface::ReadRegister
virtual bool ReadRegister(const ULWord inRegNum, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Reads all or part of the 32-bit contents of a specific register (real or virtual) on the AJA device....
Definition: ntv2macdriverinterface.cpp:389
NTV2RegInfo::registerValue
ULWord registerValue
My register value to use in a ReadRegister or WriteRegister call.
Definition: ntv2publicinterface.h:3934
NTV2IpErrMBStatusFail
@ NTV2IpErrMBStatusFail
Definition: ntv2enums.h:4257
FIFO_SIZE
#define FIFO_SIZE
Definition: ntv2mailbox.h:36
CNTV2MailBox::ReadChannelRegister
bool ReadChannelRegister(const ULWord inReg, ULWord &outValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0x0)
Definition: ntv2mailbox.cpp:237
CNTV2MailBox::AcquireMailbox
bool AcquireMailbox()
Definition: ntv2mailbox.cpp:270
NTV2IpErrWriteSeqToMB
@ NTV2IpErrWriteSeqToMB
Definition: ntv2enums.h:4246
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::void
j template void())
Definition: json.hpp:4893
MB_tWRDATA
#define MB_tWRDATA
Definition: ntv2mailbox.h:16
CNTV2MailBox::waitSOM
bool waitSOM(uint32_t timeout)
Definition: ntv2mailbox.cpp:183
NTV2IpErrTimeoutNoSeq
@ NTV2IpErrTimeoutNoSeq
Definition: ntv2enums.h:4249
CNTV2MailBox::txBuf
uint32_t txBuf[1024+1]
Definition: ntv2mailbox.h:100
NTV2IpErrTimeoutNoSOM
@ NTV2IpErrTimeoutNoSOM
Definition: ntv2enums.h:4248
CNTV2MailBox::mIpInternalErrorString
std::string mIpInternalErrorString
Definition: ntv2mailbox.h:82
ULWord
uint32_t ULWord
Definition: ajatypes.h:253
NTV2IpErrNone
@ NTV2IpErrNone
Definition: ntv2enums.h:4231
CNTV2Card::ReleaseMailBoxLock
virtual bool ReleaseMailBoxLock(void)
Definition: ntv2register.cpp:4495
NTV2IpErrAcquireMBTimeout
@ NTV2IpErrAcquireMBTimeout
Definition: ntv2enums.h:4253
NTV2IpErrWriteCountToMB
@ NTV2IpErrWriteCountToMB
Definition: ntv2enums.h:4247
CNTV2MailBox::~CNTV2MailBox
~CNTV2MailBox()
Definition: ntv2mailbox.cpp:55
CNTV2MailBox::WriteChannelRegister
bool WriteChannelRegister(ULWord reg, ULWord value, ULWord mask=0xFFFFFFFF, ULWord shift=0x0)
Definition: ntv2mailbox.cpp:246
CLOCK_MONOTONIC
#define CLOCK_MONOTONIC
Definition: pthreadsextra.h:23
SAREK_REGS
#define SAREK_REGS
Definition: ntv2registersmb.h:54
CNTV2MailBox::waitTxReady
bool waitTxReady(uint32_t timeout)
Definition: ntv2mailbox.cpp:217
ntv2utils.h
Declares numerous NTV2 utility functions.
CNTV2MailBox::waitRxReady
bool waitRxReady(uint32_t timeout)
Definition: ntv2mailbox.cpp:204
CNTV2Card
I interrogate and control an AJA video/audio capture/playout device.
Definition: ntv2card.h:28
MB_tRDDATA
#define MB_tRDDATA
Definition: ntv2mailbox.h:17
NTV2IpErrWriteSOMToMB
@ NTV2IpErrWriteSOMToMB
Definition: ntv2enums.h:4245
CNTV2MailBox::mIpErrorCode
NTV2IpError mIpErrorCode
Definition: ntv2mailbox.h:81
ntv2mailbox.h
Declares the CNTV2MailBox class.
NTV2IpErrNoResponseFromMB
@ NTV2IpErrNoResponseFromMB
Definition: ntv2enums.h:4252
NTV2IpErrExceedsFifo
@ NTV2IpErrExceedsFifo
Definition: ntv2enums.h:4251
CNTV2MailBox::sendMsg
bool sendMsg(char *msg, uint32_t timeout)
Definition: ntv2mailbox.cpp:94
CNTV2MailBox::getResponse
void getResponse(std::string &response)
Definition: ntv2mailbox.cpp:301
CNTV2Card::BankSelectReadRegister
virtual bool BankSelectReadRegister(const NTV2RegInfo &inBankSelect, NTV2RegInfo &inOutRegInfo)
Reads the given set of registers from the bank specified in position 0.
Definition: ntv2register.cpp:4621
CNTV2Card::WaitForOutputVerticalInterrupt
virtual bool WaitForOutputVerticalInterrupt(const NTV2Channel inChannel=NTV2_CHANNEL1, UWord inRepeatCount=1)
Efficiently sleeps the calling thread/process until the next one or more field (interlaced video) or ...
Definition: ntv2subscriptions.cpp:134
SAREK_MAILBOX
#define SAREK_MAILBOX
Definition: ntv2registersmb.h:56
MBS_TX_FULL
#define MBS_TX_FULL
Definition: ntv2mailbox.h:27
SAREK_MB_PRESENT
#define SAREK_MB_PRESENT
Definition: ntv2registersmb.h:200
MBS_RX_EMPTY
#define MBS_RX_EMPTY
Definition: ntv2mailbox.h:26
CNTV2MailBox::rcvMsg
bool rcvMsg(uint32_t timeout)
Definition: ntv2mailbox.cpp:102
CNTV2MailBox::rxReady
bool rxReady()
Definition: ntv2mailbox.cpp:198
CNTV2MailBox::getError
void getError(std::string &error)
Definition: ntv2mailbox.cpp:257
clock_gettime
int clock_gettime(clockid_t clk_id, struct timespec *tp)
Definition: pthreadsextra.cpp:12
NTV2IpErrorEnumToString
std::string NTV2IpErrorEnumToString(const NTV2IpError inIpErrorEnumValue)
Definition: ntv2utils.cpp:7350
MB_tSTATUS
#define MB_tSTATUS
Definition: ntv2mailbox.h:18
NTV2IpErrTimeoutNoBytecount
@ NTV2IpErrTimeoutNoBytecount
Definition: ntv2enums.h:4250
CNTV2MacDriverInterface::WriteRegister
virtual bool WriteRegister(const ULWord inRegNum, const ULWord inValue, const ULWord inMask=0xFFFFFFFF, const ULWord inShift=0)
Updates or replaces all or part of the 32-bit contents of a specific register (real or virtual) on th...
Definition: ntv2macdriverinterface.cpp:430
NTV2RegInfo
Everything needed to call CNTV2Card::ReadRegister or CNTV2Card::WriteRegister functions.
Definition: ntv2publicinterface.h:3931
CNTV2MailBox::CNTV2MailBox
CNTV2MailBox(CNTV2Card &device)
Definition: ntv2mailbox.cpp:44
CNTV2Card::BankSelectWriteRegister
virtual bool BankSelectWriteRegister(const NTV2RegInfo &inBankSelect, const NTV2RegInfo &inRegInfo)
Writes the given set of registers to the bank specified at position 0.
Definition: ntv2register.cpp:4610
CNTV2MailBox::writeMB
bool writeMB(uint32_t val, uint32_t timeout=50)
Definition: ntv2mailbox.cpp:163
CNTV2MailBox::ReleaseMailbox
void ReleaseMailbox()
Definition: ntv2mailbox.cpp:291