Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

Instrument.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // =STS=> Instrument.cpp[1728].aa15 open SMID:15
  2. //////////////////////////////////////////////////////////////////////
  3. //
  4. // (c) Copyright 2003-2008 Cyberkinetics, Inc.
  5. // (c) Copyright 2008-2011 Blackrock Microsystems
  6. //
  7. // $Workfile: Instrument.cpp $
  8. // $Archive: /Cerebus/Human/WindowsApps/Central/Instrument.cpp $
  9. // $Revision: 5 $
  10. // $Date: 4/26/05 2:57p $
  11. // $Author: Kkorver $
  12. //
  13. // $NoKeywords: $
  14. //
  15. //////////////////////////////////////////////////////////////////////
  16. #include "StdAfx.h"
  17. #include <algorithm> // Use C++ default min and max implementation.
  18. #include "debugmacs.h"
  19. #include "Instrument.h"
  20. // table of starting ip addresses for each NSP (128 channels)
  21. // indexed by NSP number:
  22. #define RANGESIZE 16
  23. const char g_NSP_IP[cbMAXOPEN][16] =
  24. { NSP_IN_ADDRESS,
  25. "192.168.137.17",
  26. "192.168.137.33",
  27. "192.168.137.49"
  28. };
  29. //////////////////////////////////////////////////////////////////////
  30. // Construction/Destruction
  31. //////////////////////////////////////////////////////////////////////
  32. Instrument::Instrument() :
  33. m_nInPort(NSP_IN_PORT), m_nOutPort(NSP_OUT_PORT),
  34. m_szInIP(NSP_IN_ADDRESS), m_szOutIP(NSP_OUT_ADDRESS)
  35. {
  36. }
  37. Instrument::~Instrument()
  38. {
  39. }
  40. // Author & Date: Ehsan Azar 15 May 2012
  41. // Purpose: Set networking parameters to overwrite default addresses
  42. // Note: must be called before Open for parameters to work
  43. // Inputs:
  44. // nInPort - the input port through which instrument connects to me
  45. // nOutPort - the output port to connect to in order to connect to the instrument
  46. // szInIP - Cerebus IP address
  47. // szOutIP - Instrument IP address
  48. void Instrument::SetNetwork(int nInPort, int nOutPort, LPCSTR szInIP, LPCSTR szOutIP)
  49. {
  50. m_nInPort = nInPort;
  51. m_nOutPort = nOutPort;
  52. m_szInIP = szInIP;
  53. m_szOutIP = szOutIP;
  54. }
  55. // Author & Date: Tom Richins 2 May 2011
  56. // Purpose: Open a network socket to the NSP instrument allowing for multiple NSPs
  57. // If NSP is not detected, based on nStartupOptionsFlags, other addresses are tried
  58. // Inputs:
  59. // nStartupOptionsFlags - the network startup option
  60. // nNSPnum - index of nsp
  61. // Outputs:
  62. // Returns the error code (0 means success)
  63. cbRESULT Instrument::OpenNSP(STARTUP_OPTIONS nStartupOptionsFlags, uint16_t nNSPnum)
  64. {
  65. m_szInIP = g_NSP_IP[nNSPnum < 4 ? nNSPnum : 0];
  66. return Open(nStartupOptionsFlags);
  67. }
  68. // Author & Date: Ehsan Azar 12 March 2010
  69. // Purpose: Open a network socket to the NSP instrument
  70. // If NSP is not detected, based on nStartupOptionsFlags, other addresses are tried
  71. // Inputs:
  72. // nStartupOptionsFlags - the network startup option
  73. // bBroadcast - establish a broadcast socket
  74. // bDontRoute - establish a direct socket with no routing or gateway
  75. // bNonBlocking - establish a non-blocking socket
  76. // nRecBufSize - the system receive-buffer size allocated for this socket
  77. // Outputs:
  78. // Returns the error code (0 means success)
  79. cbRESULT Instrument::Open(STARTUP_OPTIONS nStartupOptionsFlags, bool bBroadcast, bool bDontRoute, bool bNonBlocking, int nRecBufSize)
  80. {
  81. int nRange= RANGESIZE;
  82. int nInPort = m_nInPort;
  83. int nOutPort = m_nOutPort;
  84. LPCSTR szInIP = m_szInIP;
  85. LPCSTR szOutIP = m_szOutIP;
  86. bool bVerbose = false;
  87. if ((OPT_ANY_IP == nStartupOptionsFlags) || (OPT_LOOPBACK == nStartupOptionsFlags))
  88. {
  89. bVerbose = true; // We want to see the transactions
  90. nRange = 130;
  91. #ifdef WIN32
  92. AllocConsole();
  93. #else
  94. // Do nothing. _cprintf is defined as printf
  95. #endif
  96. }
  97. else if (OPT_LOCAL == nStartupOptionsFlags)
  98. {
  99. // If local instrument then connect to it
  100. szInIP = LOOPBACK_ADDRESS;
  101. szOutIP = LOOPBACK_BROADCAST;
  102. nInPort = NSP_IN_PORT;
  103. nOutPort = NSP_OUT_PORT;
  104. }
  105. return m_icUDP.Open(nStartupOptionsFlags, nRange, bVerbose, szInIP, szOutIP,
  106. bBroadcast, bDontRoute, bNonBlocking, nRecBufSize, nInPort, nOutPort, cbCER_UDP_SIZE_MAX);
  107. }
  108. int Instrument::Send(void *ppkt)
  109. {
  110. uint32_t quadlettotal = (((cbPKT_GENERIC*)ppkt)->dlen) + cbPKT_HEADER_32SIZE;
  111. uint32_t cbSize = quadlettotal << 2; // number of bytes
  112. CachedPacket * pEnd = ARRAY_END(m_aicCache);
  113. CachedPacket * pCache;
  114. // Find the first location that is open
  115. for (pCache = m_aicCache; pCache != pEnd; pCache++) {
  116. if (pCache->OkToSend())
  117. break;
  118. }
  119. if (pCache == pEnd)
  120. return -1;
  121. pCache->AddPacket(ppkt, cbSize);
  122. return m_icUDP.Send(ppkt, cbSize);
  123. }
  124. int Instrument::Recv(void * packet)
  125. {
  126. return m_icUDP.Recv(packet);
  127. }
  128. // What is our current send mode?
  129. Instrument::ModeType Instrument::GetSendMode()
  130. {
  131. ModeType ret = static_cast<ModeType>(0);
  132. for (CachedPacket * pCache = m_aicCache; pCache != ARRAY_END(m_aicCache); ++pCache)
  133. {
  134. ret = std::max(ret, pCache->GetMode());
  135. }
  136. return ret;
  137. }
  138. // A packet has come in...
  139. void Instrument::TestForReply(void * pPacket)
  140. {
  141. // Give everyone a chance to see if this is an important packet
  142. for (CachedPacket * pCache = m_aicCache; pCache != ARRAY_END(m_aicCache); ++pCache)
  143. {
  144. pCache->CheckForReply(pPacket);
  145. }
  146. }
  147. void Instrument::Close()
  148. {
  149. m_icUDP.Close();
  150. }
  151. void Instrument::Standby()
  152. {
  153. cbPKT_SYSINFO pktsysinfo;
  154. pktsysinfo.time = 0;
  155. pktsysinfo.chid = 0x8000;
  156. pktsysinfo.type = cbPKTTYPE_SYSSETRUNLEV;
  157. pktsysinfo.dlen = cbPKTDLEN_SYSINFO;
  158. pktsysinfo.runlevel = cbRUNLEVEL_HARDRESET;
  159. Send(&pktsysinfo);
  160. return;
  161. }
  162. void Instrument::Shutdown()
  163. {
  164. cbPKT_SYSINFO pktsysinfo;
  165. pktsysinfo.time = 0;
  166. pktsysinfo.chid = 0x8000;
  167. pktsysinfo.type = cbPKTTYPE_SYSSETRUNLEV;
  168. pktsysinfo.dlen = cbPKTDLEN_SYSINFO;
  169. pktsysinfo.runlevel = cbRUNLEVEL_SHUTDOWN;
  170. Send(&pktsysinfo);
  171. return;
  172. }
  173. // Author & Date: Kirk Korver 17 Jun 2003
  174. // Purpose: receive a buffer from the "loopback" area. In other words, get it from our
  175. // local buffer. It wasn't really sent
  176. // Inputs:
  177. // pBuffer - Where to stuff the packet
  178. // pPacketData - the packet put put in this location
  179. // Outputs:
  180. // the number of bytes read, or 0 if no data was found
  181. int Instrument::LoopbackRecvLow(void * pBuffer, void * pPacketData, uint32_t nInstance)
  182. {
  183. uint32_t nIdx = cb_library_index[nInstance];
  184. cbPKT_GENERIC * pPacket = static_cast<cbPKT_GENERIC *>(pPacketData);
  185. // find the length of the packet
  186. const uint32_t quadlettotal = (pPacket->dlen) + cbPKT_HEADER_32SIZE;
  187. const int cbSize = quadlettotal << 2; // How many bytes are there
  188. // copy the packet
  189. memcpy(pBuffer, pPacket, cbSize);
  190. // complete the packet processing by clearing the packet from the xmt buffer
  191. memset(pPacket, 0, cbSize);
  192. cb_xmt_local_buffer_ptr[nIdx]->transmitted++;
  193. cb_xmt_local_buffer_ptr[nIdx]->tailindex += quadlettotal;
  194. if ((cb_xmt_local_buffer_ptr[nIdx]->tailindex) > (cb_xmt_local_buffer_ptr[nIdx]->bufferlen - (cbCER_UDP_SIZE_MAX / 4)))
  195. {
  196. cb_xmt_local_buffer_ptr[nIdx]->tailindex = 0;
  197. }
  198. return cbSize;
  199. }
  200. // Called every 10 ms...use for "resending"
  201. // Outputs:
  202. // TRUE if any instrument error has happened; FALSE otherwise
  203. bool Instrument::Tick()
  204. {
  205. // What is the end?
  206. CachedPacket * pEnd = ARRAY_END(m_aicCache);
  207. CachedPacket * pFound;
  208. // Find the first case where {item}.Tick(m_icUDP) == true
  209. for (pFound = m_aicCache; pFound != pEnd; pFound++)
  210. {
  211. if (pFound->Tick(m_icUDP))
  212. break;
  213. }
  214. // If I've reached the end, then none are true
  215. return pFound != pEnd;
  216. }
  217. void Instrument::Reset(int nMaxTickCount, int nMaxRetryCount)
  218. {
  219. // Call everybody's reset member function
  220. CachedPacket * pCache;
  221. for (pCache = m_aicCache; pCache != ARRAY_END(m_aicCache); pCache++)
  222. {
  223. pCache->Reset(nMaxTickCount, nMaxRetryCount);
  224. }
  225. }
  226. // Author & Date: Kirk Korver 05 Jan 2003
  227. // Purpose: Is it OK to send a new packet out?
  228. // Outputs:
  229. // TRUE if it is OK to send; FALSE if not
  230. bool Instrument::OkToSend()
  231. {
  232. CachedPacket * pEnd = ARRAY_END(m_aicCache);
  233. CachedPacket * pFound;
  234. // Find the first location that is open
  235. for (pFound = m_aicCache; pFound != pEnd; pFound++)
  236. {
  237. if (pFound->OkToSend())
  238. break;
  239. }
  240. return (pFound != pEnd);
  241. }
  242. Instrument::CachedPacket::CachedPacket()
  243. {
  244. Reset();
  245. }
  246. // Stop trying to send packets and restart
  247. void Instrument::CachedPacket::Reset(int nMaxTickCount, int nMaxRetryCount)
  248. {
  249. m_enSendMode = MT_OK_TO_SEND; // What is our current send mode?
  250. m_nTickCount = m_nMaxTickCount = nMaxTickCount; // How many ticks have passed since we sent?
  251. m_nRetryCount = m_nMaxRetryCount = nMaxRetryCount; // How many times have we re-sent this packet?
  252. }
  253. // Save this packet
  254. bool Instrument::CachedPacket::AddPacket(void * pPacket, int cbBytes)
  255. {
  256. ASSERT((unsigned int)cbBytes <= sizeof(m_abyPacket));
  257. memcpy(m_abyPacket, pPacket, cbBytes);
  258. m_cbPacketBytes = cbBytes;
  259. m_enSendMode = MT_WAITING_FOR_REPLY;
  260. m_nTickCount = m_nMaxTickCount; // How many ticks have passed since we sent?
  261. m_nRetryCount = m_nMaxRetryCount; // How many times have we re-sent this packet?
  262. // TRACE("Outgoing Pkt Type: 0x%2X\n", ((cbPKT_GENERIC*)pPacket)->type);
  263. return true;
  264. }
  265. // A packet came in, compare to see if necessary
  266. void Instrument::CachedPacket::CheckForReply(void * pPacket)
  267. {
  268. if (m_enSendMode == MT_WAITING_FOR_REPLY)
  269. {
  270. cbPKT_GENERIC * pIn = static_cast<cbPKT_GENERIC *>(pPacket);
  271. cbPKT_GENERIC * pOut = reinterpret_cast<cbPKT_GENERIC *>(m_abyPacket);
  272. /*
  273. DEBUG_CODE
  274. (
  275. // If it is a "hearbeat" packet, then just don't look at it
  276. if (pIn->chid == 0x8000 && pIn->type == 0)
  277. return;
  278. TRACE("Incoming Pkt chid: 0x%04X type: 0x%02X, SENT chid: 0x%04X, type: 0x%02X, chan: %d\n",
  279. pIn->chid, pIn->type,
  280. pOut->chid, pOut->type,
  281. ((cbPKT_CHANINFO *)(pOut))->chan );
  282. );
  283. */
  284. if (pIn->type != (pOut->type & ~0x80)) // mask off the highest bit
  285. return;
  286. if (pIn->chid != pOut->chid)
  287. return;
  288. // If this is a "configuration type packet"
  289. // The logic works because Chanset is 0xC0 and all config packets are 0xC?
  290. // It will also work out because the 0xD0 family of packets will come in here
  291. // and their 1st value is channel.
  292. if ((pOut->type & cbPKTTYPE_CHANSET) == cbPKTTYPE_CHANSET)
  293. {
  294. if (pOut->dlen)
  295. {
  296. cbPKT_CHANINFO * pChanIn = static_cast<cbPKT_CHANINFO *>(pPacket);
  297. cbPKT_CHANINFO * pChanOut = reinterpret_cast<cbPKT_CHANINFO *>(m_abyPacket);
  298. if (pChanIn->chan != pChanOut->chan)
  299. return;
  300. }
  301. }
  302. // If we get this far, then we must have a match
  303. m_enSendMode = MT_OK_TO_SEND;
  304. }
  305. }
  306. // Called every 10 ms...use for "resending"
  307. // Outputs:
  308. // TRUE if any instrument error has happened; FALSE otherwise
  309. bool Instrument::CachedPacket::Tick(const UDPSocket & rcUDP)
  310. {
  311. if (m_enSendMode == MT_WAITING_FOR_REPLY)
  312. {
  313. if (--m_nTickCount <= 0) // If time to resend
  314. {
  315. if (--m_nRetryCount > 0) // If not too many retries
  316. {
  317. TRACE("********************Resending packet******************* type: 0x%02X\n", ((cbPKT_GENERIC *)m_abyPacket)->type );
  318. rcUDP.Send(m_abyPacket, m_cbPacketBytes);
  319. m_nTickCount = m_nMaxTickCount;
  320. }
  321. else
  322. {
  323. // true means that we have an error here
  324. return true;
  325. }
  326. }
  327. }
  328. return false;
  329. }