Skip to content

Commit 680c375

Browse files
committed
improved pattern player command line option parsing. values can be dec or hex.
1 parent 3df0909 commit 680c375

File tree

1 file changed

+124
-78
lines changed

1 file changed

+124
-78
lines changed

src/CommandLineUtilities/ProgramPatternPlayer.cxx

Lines changed: 124 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -32,46 +32,83 @@ using namespace o2::roc;
3232
namespace po = boost::program_options;
3333
using namespace boost::multiprecision;
3434

35-
// 128-bit hex string parser
35+
// print uin128_t value as a readable hexa value
36+
void print_uint128(uint128_t v) {
37+
printf ("0x ");
38+
for (int k = 8; k > 0; k--) {
39+
printf("%04X ", (unsigned int)((v >> ((k-1)*16)) & 0xffff));
40+
}
41+
printf("\n");
42+
}
43+
44+
// 128-bit string parser (both hex and decimal)
3645
// nBits specifies the maximum allowed bit width
3746
// throws exception on error
38-
uint128_t parsePattern(const std::string &s, int nBits = 128) {
39-
uint128_t v = 0;
40-
if (strncmp(s.c_str(), "0x", 2) || (s.length() <= 2)) {
41-
BOOST_THROW_EXCEPTION(InvalidOptionValueException()
42-
<< ErrorInfo::Message("Pattern must be hexadecimal"));
47+
uint128_t parsePattern(const std::string &s, unsigned int nBits = 128, const std::string &name = "") {
48+
if (nBits > 128) {
49+
nBits = 128;
4350
}
44-
for (unsigned int i=2; i<s.length(); i++) {
45-
int c = s[i];
46-
uint128_t x = 0;
47-
if ( ( c >= '0') && ( c <= '9')) {
48-
x = c - '0';
49-
} else if ( ( c >= 'A') && ( c <= 'F')) {
50-
x = 10 + c - 'A';
51-
} else if ( ( c >= 'a') && ( c <= 'f')) {
52-
x = 10 + c - 'a';
53-
} else {
51+
uint128_t v = 0;
52+
uint128_t vmax = (((uint128_t)1) << nBits) - 1;
53+
std::string error = "Parsing option " + name + " : ";
54+
auto addDigit = [&] (uint128_t digit, uint128_t base) {
55+
bool overflow = 0;
56+
if (digit >= base) {
57+
overflow =1;
58+
} else if (v > (vmax / base)) {
59+
overflow = 1;
60+
}
61+
v = v * ((uint128_t)base);
62+
if (v > vmax - ((uint128_t)digit)) {
63+
overflow = 1;
64+
}
65+
v = v + ((uint128_t)digit);
66+
if (v > vmax) {
67+
overflow = 1;
68+
}
69+
if (overflow) {
5470
BOOST_THROW_EXCEPTION(InvalidOptionValueException()
55-
<< ErrorInfo::Message("Pattern must be hexadecimal"));
71+
<< ErrorInfo::Message(error + "Value exceeds " + std::to_string(nBits) + " bits"));
5672
}
57-
v = (v << 4) + x;
58-
59-
/*
60-
// print value
61-
for (int k=8; k > 0; k--) {
62-
printf("%04X ", (unsigned int)((v >> ((k-1)*16)) & 0xffff));
73+
return;
74+
};
75+
if (!strncmp(s.c_str(), "0x", 2)) {
76+
// hexadecimal string
77+
for (unsigned int i=2; i<s.length(); i++) {
78+
uint8_t c = s[i];
79+
uint128_t x = 0;
80+
if ( ( c >= '0') && ( c <= '9')) {
81+
x = c - '0';
82+
} else if ( ( c >= 'A') && ( c <= 'F')) {
83+
x = 10 + c - 'A';
84+
} else if ( ( c >= 'a') && ( c <= 'f')) {
85+
x = 10 + c - 'a';
86+
} else {
87+
BOOST_THROW_EXCEPTION(InvalidOptionValueException()
88+
<< ErrorInfo::Message(error + "Value has wrong hexadecimal syntax"));
89+
}
90+
addDigit(x, (uint128_t)16);
91+
}
92+
} else {
93+
// decimal string
94+
for (unsigned int i=0; i<s.length(); i++) {
95+
uint8_t c = s[i];
96+
uint128_t x = 0;
97+
if ( ( c >= '0') && ( c <= '9')) {
98+
x = c - '0';
99+
} else {
100+
BOOST_THROW_EXCEPTION(InvalidOptionValueException()
101+
<< ErrorInfo::Message(error + "Value has wrong decimal syntax"));
102+
}
103+
addDigit(x, (uint128_t)10);
63104
}
64-
printf("\n");
65-
*/
66-
}
67-
68-
if (((v >> nBits) != 0) || (s.length() - 2 > 32)) {
69-
BOOST_THROW_EXCEPTION(InvalidOptionValueException()
70-
<< ErrorInfo::Message("Pattern exceeds " + std::to_string(nBits) + " bits"));
71105
}
72106
return v;
73107
}
74108

109+
110+
111+
75112
class ProgramPatternPlayer : public Program
76113
{
77114
public:
@@ -84,42 +121,22 @@ class ProgramPatternPlayer : public Program
84121
virtual void addOptions(boost::program_options::options_description& options)
85122
{
86123
Options::addOptionCardId(options);
87-
options.add_options()("pat0",
88-
po::value<std::string>(&mOptions.pat0),
89-
"80-bit pat0 pattern in hex");
90-
options.add_options()("pat1",
91-
po::value<std::string>(&mOptions.pat1),
92-
"80-bit pat1 pattern in hex");
93-
options.add_options()("pat2",
94-
po::value<std::string>(&mOptions.pat2),
95-
"80-bit pat2 pattern in hex");
96-
options.add_options()("pat3",
97-
po::value<std::string>(&mOptions.pat3),
98-
"80-bit pat3 pattern in hex");
99-
options.add_options()("pat1-length",
100-
po::value<uint32_t>(&mOptions.info.pat1Length),
101-
"pat1 pattern's length");
102-
options.add_options()("pat1-delay",
103-
po::value<uint32_t>(&mOptions.info.pat1Delay),
104-
"pat1 pattern's delay");
105-
options.add_options()("pat2-length",
106-
po::value<uint32_t>(&mOptions.info.pat2Length),
107-
"pat2 pattern's length");
108-
options.add_options()("pat2-trigger-counters",
109-
po::value<uint32_t>(&mOptions.info.pat2TriggerTF),
110-
"Trigger counters for pat2: TF[31:20] ORBIT[19:12] BC[11:0]");
111-
options.add_options()("pat3-length",
112-
po::value<uint32_t>(&mOptions.info.pat3Length),
113-
"pat3 pattern's length");
114-
options.add_options()("pat1-trigger-select",
115-
po::value<uint32_t>(&mOptions.info.pat1TriggerSelect),
116-
"Select trigger for pat1");
117-
options.add_options()("pat2-trigger-select",
118-
po::value<uint32_t>(&mOptions.info.pat2TriggerSelect),
119-
"Select trigger for pat2");
120-
options.add_options()("pat3-trigger-select",
121-
po::value<uint32_t>(&mOptions.info.pat3TriggerSelect),
122-
"Select trigger for pat3");
124+
125+
optionValues.reserve(16); // need to keep same variable addresses
126+
127+
addOptionValue(options, "pat0", "80-bit pat0 pattern", &mOptions.info.pat0, 80);
128+
addOptionValue(options, "pat1", "80-bit pat1 pattern", &mOptions.info.pat1, 80);
129+
addOptionValue(options, "pat2", "80-bit pat2 pattern", &mOptions.info.pat2, 80);
130+
addOptionValue(options, "pat3", "80-bit pat3 pattern", &mOptions.info.pat3, 80);
131+
addOptionValue(options, "pat1-length", "pat1 pattern's length", &mOptions.info.pat1Length);
132+
addOptionValue(options, "pat1-delay", "pat1 pattern's delay", &mOptions.info.pat1Delay);
133+
addOptionValue(options, "pat2-length", "pat2 pattern's length", &mOptions.info.pat2Length);
134+
addOptionValue(options, "pat2-trigger-counters", "Trigger counters for pat2: TF[31:20] ORBIT[19:12] BC[11:0]", &mOptions.info.pat2TriggerTF);
135+
addOptionValue(options, "pat3-length", "pat3 pattern's length", &mOptions.info.pat3Length);
136+
addOptionValue(options, "pat1-trigger-select", "Select trigger for pat1", &mOptions.info.pat1TriggerSelect);
137+
addOptionValue(options, "pat2-trigger-select", "Select trigger for pat2", &mOptions.info.pat2TriggerSelect);
138+
addOptionValue(options, "pat3-trigger-select", "Select trigger for pat3", &mOptions.info.pat3TriggerSelect);
139+
123140
options.add_options()("execute-pat1-at-start",
124141
po::bool_switch(&mOptions.info.exePat1AtStart)->default_value(false),
125142
"Enable automatically sending a pat1 pattern when runenable goes high");
@@ -150,18 +167,8 @@ class ProgramPatternPlayer : public Program
150167
return;
151168
}
152169

153-
if (mOptions.pat0.length()) {
154-
mOptions.info.pat0 = parsePattern(mOptions.pat0, 80);
155-
}
156-
if (mOptions.pat1.length()) {
157-
mOptions.info.pat1 = parsePattern(mOptions.pat1, 80);
158-
}
159-
if (mOptions.pat2.length()) {
160-
mOptions.info.pat2 = parsePattern(mOptions.pat2, 80);
161-
}
162-
if (mOptions.pat3.length()) {
163-
mOptions.info.pat3 = parsePattern(mOptions.pat3, 80);
164-
}
170+
// convert input strings to numbers
171+
parseOptionValues();
165172

166173
auto cruBar2 = std::dynamic_pointer_cast<CruBar>(bar2);
167174
if (!mOptions.readBack) {
@@ -199,6 +206,45 @@ class ProgramPatternPlayer : public Program
199206
PatternPlayer::Info info;
200207
bool readBack = false;
201208
} mOptions;
209+
210+
struct OptionValue {
211+
public:
212+
enum OptionValueType {UINT32, UINT64, UINT128};
213+
std::string name; // option name
214+
std::string value; // string value
215+
void * destination; // variable assigned when parsing value
216+
unsigned int bitWidth; // maximum bit width allowed
217+
OptionValueType type; // variable type
218+
}; // namespace option
219+
220+
std::vector<OptionValue> optionValues;
221+
222+
// register 32bit option value
223+
void addOptionValue(boost::program_options::options_description& options, const char *name, const char *description, uint32_t *destinationVariable, unsigned int bitWidth = 32) {
224+
optionValues.push_back({name, "", destinationVariable, bitWidth, OptionValue::OptionValueType::UINT32});
225+
options.add_options()(name, po::value<std::string>(&(optionValues.back().value)), description);
226+
}
227+
228+
// register 128bit option value
229+
void addOptionValue(boost::program_options::options_description& options, const char *name, const char *description, uint128_t *destinationVariable, unsigned int bitWidth = 128) {
230+
optionValues.push_back({name, "", destinationVariable, bitWidth, OptionValue::OptionValueType::UINT128});
231+
options.add_options()(name, po::value<std::string>(&(optionValues.back().value)), description);
232+
}
233+
234+
// parse option values and assign corresponding variables
235+
void parseOptionValues() {
236+
for(const auto &opt : optionValues) {
237+
if (opt.value.length()) {
238+
uint128_t v;
239+
v = parsePattern(opt.value, opt.bitWidth, opt.name);
240+
if (opt.type == OptionValue::OptionValueType::UINT32) {
241+
*(static_cast<uint32_t *>(opt.destination)) = (uint32_t)v;
242+
} else if (opt.type == OptionValue::OptionValueType::UINT128) {
243+
*(static_cast<uint128_t *>(opt.destination)) = v;
244+
}
245+
}
246+
}
247+
}
202248
};
203249

204250
int main(int argc, char** argv)

0 commit comments

Comments
 (0)