@@ -32,46 +32,83 @@ using namespace o2::roc;
3232namespace po = boost::program_options;
3333using 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+
75112class 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
204250int main (int argc, char ** argv)
0 commit comments