Line data Source code
1 : /**
2 : * @file DaphneMezzModule_test.cxx
3 : *
4 : * Testing configurations sender for the daphne v3
5 : *
6 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
7 : * Licensing/copyright details are in the COPYING file that you should have
8 : * received with this code.
9 : *
10 : */
11 :
12 : #include "DaphneV3Interface.hpp"
13 :
14 : #include <zmq.hpp>
15 : #include "daphnemodules/daphne_control_high.pb.h"
16 :
17 : #include <iostream>
18 : #include <string>
19 : #include <vector>
20 : #include <stdexcept>
21 : #include <cstdlib>
22 : #include <cstring>
23 : #include <chrono>
24 : #include <random>
25 :
26 :
27 :
28 : using namespace daphne;
29 : using namespace dunedaq::daphnemodules;
30 :
31 : // ------------- small helpers -------------
32 : static std::vector<zmq::message_t> recv_multipart(zmq::socket_t& s) {
33 : std::vector<zmq::message_t> frames;
34 : while (true) {
35 : zmq::message_t part;
36 : auto ok = s.recv(part, zmq::recv_flags::none);
37 : if (!ok || *ok <= 0) throw std::runtime_error("No response from slow controller");
38 : frames.emplace_back(std::move(part));
39 : if (!s.get(zmq::sockopt::rcvmore)) break;
40 : }
41 : return frames;
42 : }
43 :
44 0 : static inline uint64_t now_ns() {
45 0 : using namespace std::chrono;
46 0 : return duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count();
47 : }
48 :
49 0 : static inline std::pair<uint64_t,uint64_t> next_ids() {
50 0 : static std::mt19937_64 rng{std::random_device{}()};
51 0 : static uint64_t seq = 1;
52 0 : uint64_t t = now_ns();
53 0 : uint64_t task = (t << 16) ^ (rng() & 0xFFFF);
54 0 : uint64_t msg = (t << 1) ^ (++seq);
55 0 : task &= ((1ull<<63)-1);
56 0 : msg &= ((1ull<<63)-1);
57 0 : return {task, msg};
58 : }
59 :
60 0 : static void usage(const char* prog) {
61 0 : std::cerr << "Usage: " << prog << " [--ip <addr>] [--port <num>] [--route <name>]\n"
62 : << " " << prog << " [ip] [port]\n"
63 : << "Env: DAPHNE_IP, DAPHNE_PORT\n"
64 0 : << "Default: 10.73.137.161:9000, route=mezz/0\n";
65 0 : }
66 :
67 0 : int main(int argc, char** argv) {
68 : // ---- Defaults
69 0 : std::string ip = "10.73.137.161";
70 0 : int port = 9000;
71 0 : std::string route = "mezz/0";
72 :
73 : // ---- Env
74 0 : if (const char* eip = std::getenv("DAPHNE_IP"); eip && *eip) ip = eip;
75 0 : if (const char* ep = std::getenv("DAPHNE_PORT"); ep && *ep) { try { port = std::stoi(ep); } catch (...) {} }
76 :
77 : // ---- CLI flags (priority over env)
78 0 : for (int i = 1; i < argc; ++i) {
79 0 : if (!std::strcmp(argv[i], "--help") || !std::strcmp(argv[i], "-h")) {
80 0 : usage(argv[0]); return 0;
81 : }
82 0 : if (!std::strcmp(argv[i], "--ip") && i + 1 < argc) { ip = argv[++i]; continue; }
83 0 : if (!std::strcmp(argv[i], "--port") && i + 1 < argc) { try { port = std::stoi(argv[++i]); } catch (...) {} continue; }
84 0 : if (!std::strcmp(argv[i], "--route") && i + 1 < argc) { route = argv[++i]; continue; }
85 : }
86 : // ---- Positional args (fallback if flags not used)
87 0 : if (argc >= 2 && argv[1][0] != '-') ip = argv[1];
88 0 : if (argc >= 3 && argv[2][0] != '-') { try { port = std::stoi(argv[2]); } catch (...) {} }
89 :
90 0 : const std::string address = ip + ":" + std::to_string(port);
91 0 : const std::string endpoint = "tcp://" + address;
92 0 : std::cerr << "[SMOKE-V2] connecting to " << endpoint << " route=" << route << "\n";
93 :
94 :
95 :
96 0 : DaphneV3Interface iface( address, route);
97 :
98 0 : GOOGLE_PROTOBUF_VERIFY_VERSION;
99 :
100 : // ---- Build ConfigureRequest (same payload you used before)
101 0 : ConfigureRequest cfg;
102 0 : cfg.set_daphne_address(ip);
103 0 : cfg.set_slot(0);
104 0 : cfg.set_timeout_ms(500);
105 0 : cfg.set_biasctrl(1300);
106 0 : cfg.set_self_trigger_threshold(0x1F40);
107 0 : cfg.set_self_trigger_xcorr(0x68);
108 0 : cfg.set_tp_conf(0x0010DB35);
109 0 : cfg.set_compensator(0xFFFFFFFFFFull);
110 0 : cfg.set_inverters(0xFF00000000ull);
111 :
112 0 : for (uint32_t ch = 0; ch < 40; ++ch) {
113 0 : auto* c = cfg.add_channels();
114 0 : c->set_id(ch);
115 0 : c->set_trim(0);
116 0 : c->set_offset(2275);
117 0 : c->set_gain(1);
118 : }
119 0 : for (uint32_t afe = 0; afe < 5; ++afe) {
120 0 : auto* a = cfg.add_afes();
121 0 : a->set_id(afe);
122 0 : a->set_attenuators(1600);
123 0 : a->set_v_bias(0);
124 0 : a->mutable_adc()->set_resolution(true);
125 0 : a->mutable_adc()->set_output_format(true);
126 0 : a->mutable_adc()->set_sb_first(false);
127 0 : a->mutable_pga()->set_lpf_cut_frequency(4);
128 0 : a->mutable_pga()->set_integrator_disable(true);
129 0 : a->mutable_pga()->set_gain(0);
130 0 : a->mutable_lna()->set_clamp(0);
131 0 : a->mutable_lna()->set_gain(2);
132 0 : a->mutable_lna()->set_integrator_disable(true);
133 : }
134 :
135 : // ---- Wrap in V2 envelope
136 0 : ControlEnvelopeV2 req;
137 0 : req.set_version(2);
138 0 : req.set_dir(DIR_REQUEST);
139 0 : req.set_type(MT2_CONFIGURE_FE_REQ);
140 0 : req.set_payload(cfg.SerializeAsString());
141 0 : {
142 0 : auto [task_id, msg_id] = next_ids();
143 0 : req.set_task_id(task_id);
144 0 : req.set_msg_id(msg_id);
145 0 : req.set_timestamp_ns(now_ns());
146 0 : if (!route.empty()) req.set_route(route);
147 : }
148 :
149 0 : try {
150 : // zmq::context_t ctx(1);
151 : // zmq::socket_t sock(ctx, zmq::socket_type::dealer);
152 : // sock.set(zmq::sockopt::routing_id, "zmq-config-smoke-v2");
153 : // sock.set(zmq::sockopt::rcvtimeo, 4000);
154 : // sock.set(zmq::sockopt::sndtimeo, 4000);
155 : // sock.connect(endpoint);
156 :
157 :
158 : // send
159 : // {
160 : // std::string bytes = req.SerializeAsString();
161 : // zmq::message_t msg(bytes.size());
162 : // std::memcpy(msg.data(), bytes.data(), bytes.size());
163 : // if (!sock.send(msg, zmq::send_flags::none)) {
164 : // std::cerr << "send() timed out\n"; return 2;
165 : // }
166 : // }
167 :
168 : // // recv
169 : // auto frames = recv_multipart(sock);
170 : // const zmq::message_t& payload = frames.back();
171 :
172 : // ControlEnvelopeV2 rep;
173 : // if (!rep.ParseFromArray(payload.data(), static_cast<int>(payload.size()))) {
174 : // std::cerr << "Failed to parse ControlEnvelopeV2 reply\n"; return 3;
175 : // }
176 :
177 :
178 : // // validate V2 transport
179 : // bool ok_dir = (rep.dir() == DIR_RESPONSE);
180 : // bool ok_type = (rep.type() == MT2_CONFIGURE_FE_RESP);
181 : // bool ok_tid = (rep.task_id() == req.task_id());
182 : // bool ok_corr = (rep.correl_id() == req.msg_id());
183 : // if (!ok_dir || !ok_type || !ok_tid || !ok_corr) {
184 : // std::cerr << "Correlation/type mismatch:"
185 : // << "\n dir: got " << rep.dir() << " expect " << DIR_RESPONSE
186 : // << "\n type: got " << rep.type() << " expect " << MT2_CONFIGURE_FE_RESP
187 : // << "\n task: got " << rep.task_id() << " expect " << req.task_id()
188 : // << "\n corr: got " << rep.correl_id()<< " expect " << req.msg_id()
189 : // << "\n";
190 : // return 4;
191 : // }
192 :
193 : // // decode payload
194 : // ConfigureResponse resp;
195 : // if (!resp.ParseFromString(rep.payload())) {
196 : // std::cerr << "Failed to parse ConfigureResponse\n"; return 5;
197 : // }
198 :
199 0 : auto resp = iface.send<ConfigureResponse>( cfg.SerializeAsString(), MT2_CONFIGURE_FE_REQ, MT2_CONFIGURE_FE_RESP);
200 :
201 : // std::cout << "[V2 meta]\n";
202 : // std::cout << " task_id : " << rep.task_id() << "\n";
203 : // std::cout << " msg_id : " << rep.msg_id() << "\n";
204 : // std::cout << " correl_id : " << rep.correl_id() << "\n";
205 : // std::cout << " timestamp_ns : " << rep.timestamp_ns() << "\n";
206 : // if (!rep.route().empty())
207 : // std::cout << " route : " << rep.route() << "\n";
208 : // std::cout << "\n";
209 0 : std::cout << "Success: " << std::boolalpha << resp.success() << "\n";
210 0 : std::cout << "Message:\n" << resp.message() << "\n";
211 :
212 0 : google::protobuf::ShutdownProtobufLibrary();
213 0 : return resp.success() ? 0 : 6;
214 :
215 0 : } catch (const std::exception& e) {
216 0 : std::cerr << "Exception: " << e.what() << "\n";
217 0 : return 7;
218 0 : }
219 0 : }
|