Line data Source code
1 : #ifndef MU2EDEV_H
2 : #define MU2EDEV_H
3 :
4 : // This file (mu2edev.hh) was created by Ron Rechenmacher <ron@fnal.gov> on
5 : // Feb 13, 2014. "TERMS AND CONDITIONS" governing this file are in the README
6 : // or COPYING file. If you do not have such a file, one can be obtained by
7 : // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
8 : // $RCSfile: .emacs.gnu,v $
9 : // rev="$Revision: 1.23 $$Date: 2012/01/23 15:32:40 $";
10 :
11 : #include "mu2e_driver/mu2e_mmap_ioctl.h" //
12 :
13 : #include "mu2esim.h"
14 :
15 : #include <atomic>
16 : #include <chrono>
17 : #include <thread>
18 :
19 : /// <summary>
20 : /// This class handles the raw interaction with the mu2e device driver
21 : /// It also will pass through device commands to the mu2esim class if it is active.
22 : /// </summary>
23 : class mu2edev
24 : {
25 : public:
26 : /// <summary>
27 : /// Initialize counters and other data needed by the mu2edev class.
28 : /// Does not initialize the DTC, call init(DTC_SimMode) to do that.
29 : /// </summary>
30 : mu2edev();
31 : virtual ~mu2edev();
32 :
33 : /// <summary>
34 : /// Get the amount of time spent by the hardware executing requests, in seconds.
35 : /// Time counter is measured in nanoseconds, but this precision should not be relied upon, it's measured by the CPU
36 : /// not the hardware.
37 : /// </summary>
38 : /// <returns>Current amount of time spent in hardware calls, in seconds</returns>
39 0 : double GetDeviceTime() const { return deviceTime_ / 1000000000.0; }
40 :
41 : /// <summary>
42 : /// Reset the device time counter
43 : /// </summary>
44 0 : void ResetDeviceTime() { deviceTime_ = 0; }
45 :
46 : /// <summary>
47 : /// Get the current value of the write size counter
48 : /// </summary>
49 : /// <returns>Value of the write size counter</returns>
50 0 : size_t GetWriteSize() const { return writeSize_; }
51 :
52 : /// <summary>
53 : /// Reset the write size counter
54 : /// </summary>
55 : void ResetWriteSize() { writeSize_ = 0; }
56 :
57 : /// <summary>
58 : /// Gets the current value of the read size counter
59 : /// </summary>
60 : /// <returns>Value of the read size counter</returns>
61 0 : size_t GetReadSize() const { return readSize_; }
62 :
63 : /// <summary>
64 : /// Reset the read size counter
65 : /// </summary>
66 : void ResetReadSize() { readSize_ = 0; }
67 :
68 : /// <summary>
69 : /// Initialize the simulator if simMode requires it, otherwise set up DMA engines
70 : /// </summary>
71 : /// <param name="simMode">Desired simulation mode</param>
72 : /// <param name="dtc">Desired DTC card to use (/dev/mu2eX)</param>
73 : /// <param name="simMemoryFileName">If using simulated DTC, name of the memory file ("mu2esim.bin")</param>
74 : /// <returns>0 on success</returns>
75 : int init(DTCLib::DTC_SimMode simMode, int deviceIndex, std::string simMemoryFileName = "mu2esim.bin", const std::string& uid = "");
76 : void initDMAEngine();
77 :
78 : /// <summary>
79 : /// Reads data from the DTC.
80 : /// Returns the number of bytes read. Negative values indicate errors.
81 : /// </summary>
82 : /// <param name="chn">Channel to read</param>
83 : /// <param name="buffer">Pointer to output buffer</param>
84 : /// <param name="tmo_ms">Timeout for read</param>
85 : /// <returns>Byte count of data read into buffer. Negative value indicates error.</returns>
86 : int read_data(DTC_DMA_Engine const& chn, void** buffer, int tmo_ms);
87 : /// <summary>
88 : /// Convert a DMA buffer pointer into the receive-ring slot index [0, MU2E_NUM_RECV_BUFFS) for
89 : /// the active device on the given channel. Returns -1 if ptr falls outside the mmap'd region.
90 : /// Useful for diagnostic prints.
91 : /// </summary>
92 : int GetBufferIndex(DTC_DMA_Engine const& chn, const void* ptr) const;
93 : /// <summary>
94 : /// Release a number of buffers held by the software on the given channel
95 : /// </summary>
96 : /// <param name="chn">Channel to release</param>
97 : /// <param name="num">Number of buffers to release</param>
98 : /// <returns>0 when successful (always)</returns>
99 : int read_release(DTC_DMA_Engine const& chn, unsigned num);
100 : /// <summary>
101 : /// Release all buffers held by software on the given channel
102 : /// </summary>
103 : /// <param name="chn">Channel to release (DAQ or DCS)</param>
104 : /// <returns>0 on success</returns>
105 : int release_all(DTC_DMA_Engine const& chn);
106 : /// <summary>
107 : /// Read a DTC register
108 : /// </summary>
109 : /// <param name="address">Address to read</param>
110 : /// <param name="tmo_ms">Timeout for read</param>
111 : /// <param name="output">Pointer to output word</param>
112 : /// <returns>0 on success</returns>
113 : int read_register(uint16_t address, int tmo_ms, uint32_t* output);
114 : /// <summary>
115 : /// Write to a DTC register
116 : /// </summary>
117 : /// <param name="address">Address to write</param>
118 : /// <param name="tmo_ms">Timeout for write</param>
119 : /// <param name="data">Data to write</param>
120 : /// <returns>0 on success</returns>
121 : int write_register(uint16_t address, int tmo_ms, uint32_t data);
122 : /// <summary>
123 : /// Write to a DTC register
124 : /// </summary>
125 : /// <param name="address">Address to write</param>
126 : /// <param name="tmo_ms">Timeout for write</param>
127 : /// <param name="data">Data to write</param>
128 : /// <param name="output">Pointer to output word</param>
129 : /// <returns>0 on success</returns>
130 : int write_register_checked(uint16_t address, int tmo_ms, uint32_t data, uint32_t* output);
131 : /// <summary>
132 : /// Write out the DMA metadata to screen
133 : /// </summary>
134 : void meta_dump();
135 : /// <summary>
136 : /// Write data to the DTC
137 : /// </summary>
138 : /// <param name="chn">Channel to write</param>
139 : /// <param name="buffer">Buffer containing data to write</param>
140 : /// <param name="bytes">Size of the buffer, in bytes</param>
141 : /// <returns>0 on success</returns>
142 : int write_data(DTC_DMA_Engine const& chn, void* buffer, size_t bytes);
143 : /// <summary>
144 : /// Close the connection to the DTC
145 : /// </summary>
146 : void close();
147 :
148 : /// <summary>
149 : /// Gets the file descriptor for the mu2e block device (/dev/mu2eX)
150 : /// </summary>
151 : /// <returns>File descriptor for the mu2e block device</returns>
152 : int get_devfd_() const { return devfd_; }
153 :
154 : /// <summary>
155 : /// Get the current Device Index for this instance
156 : /// </summary>
157 : /// <returns>The current Device Index for this instance</returns>
158 0 : int getDeviceIndex() { return activeDeviceIndex_; }
159 : // int read_pcie_state(m_ioc_pcistate_t *output);
160 : // int read_dma_state(int chn, int dir, m_ioc_engstate_t *output);
161 : // int read_dma_stats(m_ioc_engstats_t *output);
162 : // int read_trn_stats(TRNStatsArray *output);
163 : // int read_test_command(m_ioc_cmd_t *output);
164 : // int write_test_command(m_ioc_cmd_t input, bool start);
165 :
166 : void begin_dcs_transaction();
167 : void end_dcs_transaction(bool force = false);
168 : bool thread_owns_dcs_lock();
169 : bool dcs_lock_free();
170 : std::string get_driver_version();
171 :
172 : /// <summary>
173 : /// Get the current DTC UID for this instance
174 : /// </summary>
175 : /// <returns>The current DTC UID for this instance</returns>
176 0 : std::string getDeviceUID() { return UID_; }
177 :
178 : /// <summary>
179 : /// For this DTC, "spy" on C2S buffers associated with chn.
180 : /// Output a small portion of each buffer to stdout until ^C.
181 : /// Only executes once per instance lifetime (or until resetSpyHasOccurred() is called) to avoid log-file chaos.
182 : /// </summary>
183 : /// <returns>No value is returned.</returns>
184 : void spy(int chn, unsigned flags, std::ostream& out = std::cout);
185 :
186 : /// <summary>
187 : /// Reset the spy-has-occurred flag so that spy() will produce output again on the next call.
188 : /// </summary>
189 0 : void resetSpyHasOccurred() { spyHasOccurred_ = false; }
190 :
191 : private:
192 : // unsigned delta_(int chn, int dir);
193 :
194 : int devfd_ = -1;
195 : volatile void* mu2e_mmap_ptrs_[MU2E_MAX_NUM_DTCS][MU2E_MAX_CHANNELS][2][2];
196 : m_ioc_get_info_t mu2e_channel_info_[MU2E_MAX_NUM_DTCS][MU2E_MAX_CHANNELS][2];
197 : unsigned buffers_held_;
198 : mu2esim* simulator_;
199 : int activeDeviceIndex_;
200 : struct DCSLock
201 : {
202 : std::atomic<std::thread::id> thread_id{std::thread::id()};
203 : std::atomic<int> lock_count{0};
204 : };
205 : static std::array<DCSLock, MU2E_MAX_NUM_DTCS> dcs_locks_;
206 :
207 : std::atomic<long long> deviceTime_;
208 : std::atomic<size_t> writeSize_;
209 : std::atomic<size_t> readSize_;
210 :
211 : std::string UID_;
212 : FILE* debugFp_ = 0;
213 : std::chrono::steady_clock::time_point lastWriteTime_;
214 : bool spyHasOccurred_ = false; ///< Limits spy() printout to a single invocation per instance lifetime (or until resetSpyHasOccurred() is called) to avoid log-file chaos.
215 : unsigned spyIteration_ = 0;
216 : };
217 :
218 : #endif
|