Skip to content

Commit 62b9e34

Browse files
kwang428yuyichao
authored andcommitted
WIP, add chn_map
1 parent 312b69a commit 62b9e34

2 files changed

Lines changed: 236 additions & 0 deletions

File tree

lib/nacs-seq/manager.cpp

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,215 @@ NACS_EXPORT() uint32_t Manager::ExpSeq::refresh_device_restart(const char *dname
275275
return uint32_t(-1);
276276
}
277277

278+
NACS_EXPORT() Manager::ExpSeq::ChnOutput* Manager::ExpSeq::get_nominal_output(uint64_t pts_per_ramp, size_t *out_sz)
279+
{
280+
// pts_per_ramp includes the first and last point, so it must be at least 2. It will be set to 2 if not the case.
281+
// Temporary insofar as keeping the start value, and pulses for this channel.
282+
struct FilledPulse {
283+
FilledPulse(uint32_t id, int64_t time, int64_t len, double (*ramp_func)(double, void*),
284+
double endvalue, bool cond)
285+
: id(id), time(time), len(len), ramp_func(ramp_func),
286+
endvalue(endvalue), cond(cond)
287+
{
288+
// empty
289+
}
290+
uint32_t id;
291+
292+
int64_t time;
293+
int64_t len; // 0 for a set pulse and nonzero for a ramp.
294+
double (*ramp_func)(double, void*);
295+
296+
double endvalue;
297+
bool cond;
298+
};
299+
struct TempChnOutput {
300+
TempChnOutput(std::string name, double start_val)
301+
: m_name(name),
302+
m_start_val(start_val)
303+
{
304+
//
305+
}
306+
std::string m_name;
307+
double m_start_val;
308+
std::vector<FilledPulse> m_pulses;
309+
std::vector<int64_t> times;
310+
std::vector<double> values;
311+
std::vector<uint32_t> pulse_ids;
312+
};
313+
uint32_t nchannels = host_seq.nchannels;
314+
auto seq_idx = host_seq.cur_seq_idx();
315+
if (nchannels == 0 || seq_idx == uint32_t(-1)) {
316+
*out_sz = 0;
317+
return nullptr;
318+
}
319+
320+
std::map<uint32_t,TempChnOutput> temp_chn_outputs;
321+
std::vector<Manager::ExpSeq::ChnOutput> outputs;
322+
323+
// Initialize the temp output for each channel.
324+
for (auto &[name, chn_id]: m_chn_map) {
325+
std::string chn_name = name;
326+
double start_val = host_seq.start_values[chn_id - 1].f64;
327+
printf("Channel %s (ID: %d) start value: %f\n", chn_name.c_str(), chn_id, start_val);
328+
temp_chn_outputs.try_emplace(chn_id - 1, chn_name, start_val);
329+
}
330+
// Collect the pulses along with their filled values for each channel.
331+
auto &bseq = host_seq.seqs[seq_idx];
332+
// Keep track of the max time
333+
int64_t max_time = 0;
334+
for (auto &pulse: bseq.pulses) {
335+
if (pulse.is_measure())
336+
continue;
337+
int64_t time = host_seq.get_time(pulse.time);
338+
// Using this call double get_value(uint32_t i, uint32_t seq_idx) const
339+
int64_t len = pulse.len == uint32_t(-1) ? 0 : round<int64_t>(host_seq.get_value(pulse.len, seq_idx));
340+
double endvalue = host_seq.get_value(pulse.endvalue, seq_idx);
341+
bool cond = pulse.cond == uint32_t(-1) ? true : (bool) host_seq.get_value(pulse.cond, seq_idx);
342+
printf("Pulse ID: %d, Channel: %d, Time: %ld, Length: %ld, End Value: %f, Condition: %d\n",
343+
pulse.id, pulse.chn, time, len, endvalue, cond);
344+
auto it = temp_chn_outputs.find(pulse.chn - 1);
345+
if (it == temp_chn_outputs.end()) {
346+
throw std::runtime_error("Missing channel ID");
347+
} else {
348+
auto &temp_output = it->second;
349+
temp_output.m_pulses.emplace_back(pulse.id, time, len, pulse.ramp_func, endvalue, cond);
350+
}
351+
}
352+
// With all the pulses, we now build our output.
353+
for (auto &[chn_id, temp_output]: temp_chn_outputs) {
354+
// First we sort them.
355+
auto &pulses = temp_output.m_pulses;
356+
std::sort(pulses.begin(), pulses.end(), [] (auto &p1, auto &p2) {
357+
if (p1.time < p2.time)
358+
return true;
359+
if (p1.time > p2.time)
360+
return false;
361+
return p1.id < p2.id;
362+
});
363+
// Start building the output with the start value
364+
auto &times = temp_output.times;
365+
auto &values = temp_output.values;
366+
auto &pulse_ids = temp_output.pulse_ids;
367+
times.push_back(0);
368+
values.push_back(temp_output.m_start_val);
369+
pulse_ids.push_back(uint32_t(-1)); // the start value is not identified with any particular pulse.
370+
auto npulses = pulses.size();
371+
for (uint32_t i = 0; i < npulses;) {
372+
auto &pulse = pulses[i];
373+
// This check should rarely execute, except if the first pulse is disabled.
374+
if (!pulse.cond) {
375+
// Skip disabled pulse
376+
i++;
377+
continue;
378+
}
379+
// Find next pulse which is important for ensuring that this set pulse will take place and
380+
// determines the end time for a potentially interrupted ramp.
381+
bool found = false;
382+
FilledPulse *next_pulse_ptr = nullptr;
383+
i++; // Move to the next pulse
384+
while (!found) {
385+
if (i >= npulses) {
386+
found = true;
387+
}
388+
else {
389+
if (pulses[i].cond) {
390+
next_pulse_ptr = &pulses[i];
391+
found = true;
392+
} else {
393+
// Skip disabled pulse
394+
i++;
395+
}
396+
}
397+
}
398+
// Below here, i does not need to be advanced!
399+
if (pulse.len == 0) {
400+
// Set pulse
401+
// Only valid if next pulse is not at the same time.
402+
if (next_pulse_ptr && (next_pulse_ptr->time <= pulse.time)) {
403+
// Skip current pulse
404+
continue;
405+
}
406+
// If previous point is not at the current time, then add a point with the previous value.
407+
if (times.back() != pulse.time) {
408+
times.push_back(pulse.time);
409+
values.push_back(values.back()); // Use the last value.
410+
pulse_ids.push_back(pulse_ids.back()); // No pulse ID for this point.
411+
}
412+
times.push_back(pulse.time);
413+
values.push_back(pulse.endvalue);
414+
pulse_ids.push_back(pulse.id);
415+
} else {
416+
// Ramp pulse
417+
// Get end time by looking for the next pulse.
418+
int64_t end_time;
419+
if (next_pulse_ptr) {
420+
end_time = min(next_pulse_ptr->time, pulse.time + pulse.len);
421+
}
422+
else {
423+
end_time = pulse.time + pulse.len;
424+
}
425+
int64_t ramp_time = end_time - pulse.time;
426+
assert(ramp_time >= 0);
427+
if (ramp_time == 0) {
428+
// If the ramp time is 0, we let the next pulse dictate what happens.
429+
continue;
430+
}
431+
// If previous point is not at the current time, then add a point with the previous value.
432+
if (times.back() != pulse.time) {
433+
times.push_back(pulse.time);
434+
values.push_back(values.back()); // Use the last value.
435+
pulse_ids.push_back(pulse_ids.back()); // No pulse ID for this point.
436+
}
437+
// Calculate the ramp with at least pts_per_ramp points.
438+
uint64_t npts = max(2, min((uint64_t) ramp_time, pts_per_ramp));
439+
for (uint64_t j = 0; j < npts; j++) {
440+
int64_t this_pt = round<int64_t>(j * ramp_time / (npts - 1));
441+
int64_t this_time = pulse.time + this_pt;
442+
times.push_back(this_time);
443+
values.push_back(pulse.ramp_func(this_pt, host_seq.values.data()));
444+
pulse_ids.push_back(pulse.id);
445+
}
446+
}
447+
}
448+
int64_t last_time = times.back();
449+
if (last_time > max_time) {
450+
max_time = last_time;
451+
}
452+
}
453+
454+
// Now, we have built our output for each channel, we need to allocate some memory to pass it onto the next user.
455+
// We also append an extra point if not already at the max time
456+
for (auto &[chn_id, temp_output]: temp_chn_outputs) {
457+
auto &times = temp_output.times;
458+
auto &values = temp_output.values;
459+
auto &pulse_ids = temp_output.pulse_ids;
460+
// If the last time is not the max time, we add an extra point with the last value.
461+
if (times.back() != max_time) {
462+
times.push_back(max_time);
463+
values.push_back(values.back());
464+
pulse_ids.push_back(pulse_ids.back());
465+
}
466+
auto names_ptr = (char*) malloc(temp_output.m_name.size() + 1);
467+
auto times_ptr = (int64_t*) malloc(times.size() * sizeof(int64_t));
468+
auto values_ptr = (double*) malloc(values.size() * sizeof(double));
469+
auto pulse_ids_ptr = (uint32_t*) malloc(pulse_ids.size() * sizeof(uint32_t));
470+
size_t out_pts = times.size(); // All sizes should be the same.
471+
memcpy(names_ptr, temp_output.m_name.data(), temp_output.m_name.size() + 1);
472+
memcpy(times_ptr, times.data(), out_pts * sizeof(int64_t));
473+
memcpy(values_ptr, values.data(), out_pts * sizeof(double));
474+
memcpy(pulse_ids_ptr, pulse_ids.data(), out_pts * sizeof(uint32_t));
475+
// Create the output object
476+
outputs.emplace_back(names_ptr, temp_output.m_name.size() + 1, times_ptr, values_ptr, pulse_ids_ptr, out_pts);
477+
}
478+
479+
// Last allocation of memory for the outputs array, which carries a bunch of addresses.
480+
auto outputs_ptr = (Manager::ExpSeq::ChnOutput*) malloc(outputs.size() * sizeof(Manager::ExpSeq::ChnOutput));
481+
memcpy(outputs_ptr, outputs.data(), outputs.size() * sizeof(Manager::ExpSeq::ChnOutput));
482+
*out_sz = outputs.size();
483+
484+
return outputs_ptr;
485+
}
486+
278487
NACS_EXPORT_ Manager::Manager()
279488
{
280489
}
@@ -319,6 +528,7 @@ NACS_EXPORT() Manager::ExpSeq *Manager::create_sequence(const uint8_t *data, siz
319528
if (dev->check_noramp(chn_id, chn_name)) {
320529
builder.noramp_chns.push_back(chn_id);
321530
}
531+
expseq->m_chn_map.emplace(name, chn_id);
322532
}
323533
add_debug("Building sequence\n");
324534
builder.buildseq();
@@ -883,4 +1093,14 @@ NACS_EXPORT() uint32_t nacs_seq_manager_expseq_refresh_device_restart(Manager::E
8831093
}, uint32_t(-1));
8841094
}
8851095

1096+
NACS_EXPORT() Manager::ExpSeq::ChnOutput*
1097+
nacs_seq_manager_expseq_get_nominal_output(
1098+
Manager::ExpSeq *expseq, uint64_t pts_per_ramp, size_t *sz)
1099+
{
1100+
return expseq->mgr().call_guarded([&] () -> Manager::ExpSeq::ChnOutput* {
1101+
return expseq->get_nominal_output(pts_per_ramp, sz);
1102+
}, nullptr);
1103+
}
1104+
1105+
8861106
}

lib/nacs-seq/manager.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ class Manager {
7777

7878
class ExpSeq {
7979
public:
80+
struct ChnOutput {
81+
ChnOutput(char *name, size_t name_sz, int64_t *times, double *values, uint32_t *pulse_ids, size_t npts)
82+
: name(name), name_sz(name_sz), times(times), values(values), pulse_ids(pulse_ids), npts(npts)
83+
{
84+
//
85+
}
86+
87+
char *name;
88+
size_t name_sz;
89+
int64_t *times;
90+
double *values;
91+
uint32_t *pulse_ids;
92+
size_t npts;
93+
};
8094
ExpSeq(Manager *mgr, CGContext *cgctx);
8195
~ExpSeq();
8296

@@ -138,8 +152,10 @@ class Manager {
138152
std::vector<uint8_t> seq_opt;
139153
};
140154
std::unique_ptr<Dump> dump;
155+
std::map<std::string,uint32_t> m_chn_map; // Tracks the mapping from channel name to index.
141156

142157
uint32_t refresh_device_restart(const char *dname);
158+
ChnOutput* get_nominal_output(uint64_t pts_per_ramp, size_t *out_sz);
143159

144160
private:
145161
template<typename Str>

0 commit comments

Comments
 (0)