iCub-main
strain.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2018 iCub Facility - Istituto Italiano di Tecnologia
3  * Author: Marco Accame
4  * email: marco.accame@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17 */
18 
19 
20 // --------------------------------------------------------------------------------------------------------------------
21 // - public interface
22 // --------------------------------------------------------------------------------------------------------------------
23 
24 #include "strain.h"
25 
26 
27 
28 // --------------------------------------------------------------------------------------------------------------------
29 // - external dependencies
30 // --------------------------------------------------------------------------------------------------------------------
31 
32 #include <cstring>
33 #include <vector>
34 #include <fstream>
35 
36 using namespace std;
37 
38 
39 
40 // --------------------------------------------------------------------------------------------------------------------
41 // - pimpl: private implementation (see scott meyers: item 22 of effective modern c++, item 31 of effective c++
42 // --------------------------------------------------------------------------------------------------------------------
43 
44 // so let me introduce to you the one and only .... pimpl
45 
46 
47 #define IMPORT_CODE_FROM_EMBOT_HW_PGA308
48 
50 {
51 
52  // marco.accame on 27jul18: i decide to use code already developed (and very well tested ....) in:
53  // namespace embot { namespace hw { namespace PGA308 {
54  // i encapluslate it under a different scope (this Impl) and I remove dependency from can protocol
55  // by changing: embot::app::canprotocol::analog::polling::PGA308cfg1
56  // with: strain::amplifier::PGA308::Registers
57  // teh two structs have the same bitmap layout. but Registers also have methods to import from and export to a can packet
58 
59 #if defined(IMPORT_CODE_FROM_EMBOT_HW_PGA308)
60 
61  struct ZDACregister
62  {
63  std::uint16_t value;
64  static const std::uint16_t Default = 0x8000;
65 
66  // ZDAC Register: Zero DAC Register (Fine Offset Adjust)
67  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
68  // content: ZD15 ZD14 ZD13 ZD12 ZD11 ZD10 ZD9 ZD8 ZD7 ZD6 ZD5 ZD4 ZD3 ZD2 ZD1 ZD0
69  // teh value x contained in the register is mapped into: +VREF/2 – (x/65536) (VREF)
70  // the possible ranges of the offset is [+VREF*0.5, -VREF*0.4999847]
71 
72  ZDACregister() : value(0) {}
73 
74  ZDACregister(std::uint16_t v) : value(v) {}
75 
76  void reset() { value = 0; }
77 
78  void set(std::uint16_t zdac) { value = zdac; }
79 
80  void setDefault() { value = ZDACregister::Default; }
81  };
82 
83  struct GDACregister
84  {
85  std::uint16_t value;
86  static const std::uint16_t Default = 0x4000;
87 
88  // GDAC Register: Gain DAC Register
89  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
90  // content: GD15 GD14 GD13 GD12 GD11 GD10 GD9 GD8 GD7 GD6 GD5 GD4 GD3 GD2 GD1 GD0
91  // the value x contained in the register is mapped into: 0.333333333 + x * (1.000000000 – 0.333333333) / 65536 = 0.333333333 + x * 1.0172526 * 10–5
92  // value of register x is: (DesiredGain – 0.333333333) / (1.0172526 x 10–5)
93  // the range of gain is [0.333333333, 0.999989824] and GDACregister::Default is 0.499999999
94 
95  GDACregister() : value(0) {}
96 
97  GDACregister(std::uint16_t v) : value(v) {}
98 
99  void reset() { value = 0; }
100 
101  void set(std::uint16_t gdac) { value = gdac; }
102 
103  void setDefault() { value = GDACregister::Default; }
104  };
105 
107  {
108  std::uint16_t value;
109 
110  static const std::uint8_t DefaultGO = 0x06; // output gain = 6.0 (0x06) OR 2.0 (0x00)
111  static const std::uint8_t DefaultGO_g_32_96 = 0x06; // output gain = 6.0 (0x06)
112  static const std::uint8_t DefaultGO_g_16_80 = 0x02; // output gain = 3.0 (0x02)
113  static const std::uint8_t DefaultGO_g_11_75 = 0x00; // output gain = 3.0 (0x00)
114  static const std::uint8_t DefaultMUX = 0x00; // VIN1= VINPositive, VIN2= VINNegative
115  static const std::uint8_t DefaultGI = 0x04; // input gain = 16
116  static const std::uint8_t DefaultOS = 0x20; // coarse offset // 0x25 0x8A
117 
118  // CFG0 Output Amplifier Gain Select, Front-End PGA Mux & Gain Select, Coarse Offset Adjust on Front-End PGA
119  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
120  // content: GO2 GO1 GO0 GI4 GI3 GI2 GI1 GI0 OS7 OS6 OS5 OS4 OS3 OS2 OS1 OS0
121 
122  CFG0register() : value(0) {}
123 
124  CFG0register(std::uint8_t GO, std::uint8_t MUX, std::uint8_t GI, std::uint8_t OS)
125  {
126  value = 0;
127  setGO(GO);
128  setMUX(MUX);
129  setGI(GI);
130  setOS(OS);
131  }
132 
133  CFG0register(std::uint16_t v) : value(v) {}
134 
135  void reset() { value = 0; }
136 
137  void setDefault() { value = 0; setGO(CFG0register::DefaultGO); setMUX(CFG0register::DefaultMUX); setGI(CFG0register::DefaultGI); setOS(CFG0register::DefaultOS); }
138 
139  // Output Amplifier Gain Select: [GO2-GO0] -> from 000b to 111b: 2.0, 2.4, 3, 3.6, 4.0, 4.5, 6.0 disable-internal-feedback
140  void setGO(std::uint8_t GO) { value |= (static_cast<std::uint8_t>(GO&0x07) << 13); }
141  std::uint8_t getGO() const { return ((value >> 13) & 0x07); }
142 
143  // Front-End PGA Mux Select: [GI4] -> 0 is [VIN1= VINN, VIN2= VINP], 1 is [VIN1= VINP, VIN2= VINN]
144  void setMUX(std::uint8_t MUX) { value |= (static_cast<std::uint8_t>(MUX&0x01) << 12); }
145  std::uint8_t getMUX() const { return ((value >> 12) & 0x01); }
146 
147  // Front-End PGA Gain Select: [GI3-GI0] -> from 0000b to 1101b: 4 6 8 12 16 32 64 100 200 400 480 600 800 960 1200 1600
148  void setGI(std::uint8_t GI) { value |= (static_cast<std::uint8_t>(GI&0x0f) << 8); }
149  std::uint8_t getGI() const { return ((value >> 8) & 0x0f); }
150 
151  // Coarse Offset Adjust on Front-End PGA: [OS7-OS0] where OS7 is sign (0 is +) and [OS6-OS0] is value. valid range is only x = [-100, +100]
152  // which maps into (x/128)(Vref)(0.0256) for a global offset range of [-0.02*V_REF, +0.02*V_REF]. V_REF is in register CFG2.COSVR[1:0]
153  void setOS(std::uint8_t OS) { value |= (static_cast<std::uint8_t>(OS&0xff)); }
154  std::uint8_t getOS() const { return ((value) & 0xff); }
155 
156  };
157 
158 
160  {
161  std::uint16_t value;
162  static const std::uint16_t Default = 0x0000;
163 
164  // CFG1 Register: Configuration Register 1
165  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
166  // content: FLT-REF FLT-IPU OU-CFG FLT-SEL CMP-SEL EXT-EN INT-EN EXT-POL INT-POL OU-EN HL2 HL1 HL0 LL2 LL1 LL0
167 
168  CFG1register() { value = 0; }
169 
170  CFG1register(std::uint16_t v) : value(v) {}
171 
172  void reset() { value = 0; }
173 
174  void set(std::uint16_t cfg1) { value = cfg1; }
175 
176  void setDefault() { value = Default; }
177  };
178 
180  {
181  std::uint16_t value;
182  static const std::uint16_t Default = 0x0400;
183 
184  // CFG2 Register: Configuration Register 2
185  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
186  // content: OWD OWD-OFF DIS-OUT NOW COSVR1 COSVR0 RESERVD DOUTSEL DOUT SD RESERVD RESERVD RESERVD RESERVD RESERVD RESERVD
187  // COSVR: 00 -> ; 01-> ; 10 -> ; 11 -> ;
188  // with COSVR = 01b, as in our Default ... we have:
189  // - Coarse Offset Range = [2.4, 3.6] V
190  // - Coarse Offset Resolution = (1/128)(VREF)(0.0427)
191  // - Coarse Offset Range = (±100mV)(VREF/3)
192  CFG2register() { value = 0; }
193 
194  CFG2register(std::uint16_t v) : value(v) {}
195 
196  void reset() { value = 0; }
197 
198  void set(std::uint16_t cfg2) { value = cfg2; }
199 
200  void setDefault() { value = Default; }
201  };
202 
203 
205  {
206  std::uint16_t value;
207  static const std::uint16_t Default = 0x0050; // where ... there is the SOFTWARE LOCK MODE (Runs from RAM) and the PGA308 operates from data written into the RAM registers from the user
208 
209  // SFTC Register: Software Control
210  // bit: 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
211  // content: RESERVD RESERVD RESERVD RESERVD RESERVD RESERVD RESERVD CHKSFLG OW-DLY SW-L2 SW-L1 SW-L0 RFB0 XP5 XP4 XP3
212  // brief description:
213  // CHKSFLG: Register Checksum Bit (Read-only) 1 = register checksum correct
214  // OW-DLY: One-Wire Delay Bit 1 = 8-bit delay from transmit to receive during One-Wire reads, 0 = 1-bit delay from transmit to receive during One-Wire reads
215  // SWL[2:0] Software Lock Mode Control 101b = SOFTWARE LOCK (Runs from RAM), etc....
216  // XP[5:3] OTP Bank Selection for Software Lock Mode If XP[5:3] = '000', then the PGA308 operates from data written into the RAM registers from the user.
217  SFTCregister() : value(0) {}
218 
219  SFTCregister(std::uint16_t v) : value(v) {}
220 
221  void reset() { value = 0; }
222 
223  void set(std::uint16_t sftc) { value = sftc; }
224 
225  void setDefault() { value = SFTCregister::Default; }
226  };
227 
228 
229 
230 
232  {
233 
234  static const std::uint16_t VREF = 8192; // the allowed values are in range [0, VREF). it must be constant ...
235 
236  std::uint16_t GD; // gain DAC. values are [0.333333333, 0.999989824]
237  std::uint8_t GI : 4; // front end gain. from 0000b to 1101b: {4 6 8 12 16 32 64 100 200 400 480 600 800 960 1200 1600}
238  std::uint8_t muxsign : 1; // the sign: 0 is +, 1 is -
239  std::uint8_t GO : 3; // output gain. from 000b to 111b: {2.0, 2.4, 3, 3.6, 4.0, 4.5, 6.0, disable-internal-feedback}
240  std::uint8_t Vcoarseoffset; // Vcoarseoffset is stored as sign+value and must be in range [-100, +100].
241  std::uint16_t Vzerodac;
242 
243  enum class Parameter { GD = 0, GI = 1, muxsign = 2, GO = 3, Vcoarseoffset = 4, Vzerodac = 5 };
244 
245  // the formulas are:
246  //
247  // from Vin to Vout
248  // Vout = ((muxsign*Vin + Vcoarseoffset)*GI + Vzerodac)*GD*GO
249  // Vout = alpha * Vin + beta
250  // alpha = muxsign*GI*GD*GO
251  // beta = (Vcoarseoffset*GI + Vzerodac)*GD*GO
252  //
253  // we use only three variables x, y, z and we keep the other fixed to default ...
254  // x -> content of register GDAC (.GD)
255  // y -> content of register CFG0.OS (.Vcoarseoffset)
256  // z -> content of register ZDAC (.Vzerodac)
257  // we thus have:
258  // alpha(x) = valueOf(GI) * valueOf(GO) * ((1/3) + ((2/3)/64k) * x)
259  // beta(x, y, z) = alpha(x) * ((1/128)*VREF*COSVR*y + (1/valueOf(GI))*VREF*(1/64k)(32k - z))
260  // for some operations we need to represent Vout as a function only of y and z, hence
261  // Vout = a * y + b * z + c
262  // a = (d/dy) Vout = (d/dy) beta = alpha(x)*(1/128)*VREF*COSVR
263  // b = (d/dz) Vout = (d/dz) beta = - alpha(x)*(1/valueOf(GI))*VREF*(1/64k)
264  // c = Vout - a*y - b*z
265 
266 
267  TransferFunctionConfig() : GD(0), GI(0), muxsign(0), GO(0), Vcoarseoffset(0), Vzerodac(0) {}
268 
269  void load(const Registers &regs)
270  {
271  GD = regs.GD;
272  GI = regs.GI;
273  muxsign = regs.S;
274  GO = regs.GO;
275  Vcoarseoffset = regs.Voffsetcoarse;
276  Vzerodac = regs.Vzerodac;
277  }
278 
279  void get(Registers &regs)
280  {
281  regs.GD = GD;
282  regs.GI = GI;
283  regs.S = muxsign;
284  regs.GO = GO;
285  regs.Voffsetcoarse = Vcoarseoffset;
286  regs.Vzerodac = Vzerodac;
287  }
288 
289  void setDefault()
290  {
291  GD = GDACregister::Default;
292  GI = CFG0register::DefaultGI;
293  muxsign = CFG0register::DefaultMUX;
294  GO = CFG0register::DefaultGO;
295  Vcoarseoffset = CFG0register::DefaultOS;
296  Vzerodac = ZDACregister::Default;
297  }
298 
299  // from internal memory to the values of the registers to be written into the amplifier
300  void obtain(CFG0register &cfg0, ZDACregister &zdac, GDACregister &gdac) const
301  {
302  cfg0.reset(); cfg0.setGO(GO); cfg0.setMUX(muxsign); cfg0.setGI(GI); cfg0.setOS(Vcoarseoffset);
303  zdac.reset(); zdac.value = Vzerodac;
304  gdac.reset(); gdac.value = GD;
305  }
306 
307  // from the registers read from the amplifier to internal memory.
308  void assign(const CFG0register &cfg0, const ZDACregister &zdac, const GDACregister &gdac)
309  {
310  GO = cfg0.getGO();
311  muxsign = cfg0.getMUX();
312  GI = cfg0.getGI();
313  Vcoarseoffset = cfg0.getOS();
314  Vzerodac = zdac.value;
315  GD = gdac.value;
316  }
317 
318  void load(const CFG0register &cfg0)
319  {
320  GO = cfg0.getGO();
321  muxsign = cfg0.getMUX();
322  GI = cfg0.getGI();
323  Vcoarseoffset = cfg0.getOS();
324  }
325 
326  void load(const ZDACregister &zdac)
327  {
328  Vzerodac = zdac.value;
329  }
330 
331  void load(const GDACregister &gdac)
332  {
333  GD = gdac.value;
334  }
335 
336  float valueOfGI()
337  {
338  static const std::uint16_t mapGI2val[16] = {4, 6, 8, 12, 16, 32, 64, 100, 200, 400, 480, 600, 800, 960, 1200, 1600};
339  return static_cast<float>(mapGI2val[GI]);
340  }
341 
342  float valueOfGO()
343  {
344  static const float mapGO2val[8] = {2.0f, 2.4f, 3.0f, 3.6f, 4.0f, 4.5f, 6.0f, 1.0f};
345  return mapGO2val[GO];
346  }
347 
348  float valueOfGD()
349  {
350  //return 0.33333f + (static_cast<float>(GD) * 0.66666f) / 65536.0f;
351  //return (1.0f + static_cast<float>(GD)/32768.0f)/3.0f;
352  return valueOfGD(GD);
353  }
354 
355  float valueOfGD(std::uint16_t x)
356  {
357  //return 0.33333f + (static_cast<float>(GD) * 0.66666f) / 65536.0f;
358  return (1.0f + static_cast<float>(x)/32768.0f)/3.0f;
359  }
360 
361  float valueOfCOR()
362  {
363  //static const float mapCOSVR2val[4] = {0.064f, 0.0427f, 0.0320f, 0.0256f};
364  //std::uint8_t cosvr2 = 1;
365  //return static_cast<float>(VREF)*(1.0f/128.0f)*mapCOSVR2val[cosvr2];
366  return 2.7328f;
367  }
368 
369  float regvco2value(std::uint8_t co)
370  { // regvco is inside [-100, +100] in sign-value format
371  std::uint8_t v = co & 0x7f;
372  if(v > 100) { v = 100; }
373  std::uint8_t negative = co >> 7;
374  return (1 == negative) ? -v : +v;
375  }
376 
377  std::uint8_t value2regvco(float v)
378  { // regvco is inside [-100, +100] in sign-value format
379  std:: uint8_t r = 0;
380  if(v > 0)
381  {
382  v = std::floor(v + 0.5f);
383  if(v > +100.0f) { v = +100.0f; }
384  r = static_cast<std::uint8_t>(v);
385  }
386  else
387  {
388  v = -v;
389  v = std::floor(v + 0.5f);
390  if(v > +100.0f) { v = +100.0f; }
391  r = static_cast<std::uint8_t>(v) | 0x80;
392  }
393 
394  return r;
395  }
396 
398  {
399  return valueOfCOR()*regvco2value(Vcoarseoffset);
400  }
401 
403  {
404  return static_cast<float>(VREF)*(1.0f/65536.0f)*(32768.0f - static_cast<float>(Vzerodac));
405  //return static_cast<float>(VREF)*(0.0000152587890625f)*(32768.0f - static_cast<float>(Vzerodac));
406  }
407 
408  float alpha()
409  {
410  //float v = valueOfGD()*valueOfGO()*valueOfGI();
411  //return (0 == muxsign) ? v : -v;
412  return alpha(GD);
413  }
414 
415  float alpha(std::uint16_t x)
416  {
417  float v = valueOfGD(x)*valueOfGO()*valueOfGI();
418  return (0 == muxsign) ? v : -v;
419  }
420 
421  float beta()
422  {
423  float gi = valueOfGI();
424  return alpha()*(valueOfCoarseOffset() + valueOfFineOffset()/gi);
425  }
426 
427  void computeOffsetParams(const std::uint16_t vout, float &a, float &b, float &c)
428  {
429  // a = (d/dy) Vout = (d/dy) beta = alpha(x)*(1/128)*VREF*COSVR = alpha(x) * COR
430  // b = (d/dz) Vout = (d/dz) beta = - alpha(x)*(1/valueOf(GI))*VREF*(1/64k)
431  // c = Vout - a*y - b*z
432  a = alpha() * valueOfCOR();
433  b = - (alpha()*static_cast<float>(VREF)/valueOfGI())/65536.0f; // valueOfGI() is always != 0
434  c = static_cast<float>(vout) - a*regvco2value(Vcoarseoffset) - b*static_cast<float>(Vzerodac);
435  }
436 
437  bool alignVOUT(const std::uint16_t vout, const std::uint16_t target, std::uint8_t &Y, std::uint16_t &Z)
438  {
439  float a, b, c;
440  computeOffsetParams(vout, a, b, c);
441  float y = (target - c - b*static_cast<float>(Vzerodac))/a; // a is always != 0
442 
443  // round and limit y ... which must be integer and inside [-100, +100] and
444  std::uint8_t tmp = value2regvco(y);
445  y = regvco2value(tmp);
446 
447  // must apply new y to ...
448  float z = (target - c - a*y)/b;
449  if((z > 65535.0f) || (z < 0.0f))
450  {
451  return false;
452  }
453  Y = value2regvco(y);
454  Z = static_cast<std::uint16_t>(std::floor(z + 0.5f));
455  Vcoarseoffset = Y;
456  Vzerodac = Z;
457 
458  return true;
459  }
460 
461  bool setalpha(float a)
462  {
463  float xgd = 98304.0f * (a/(valueOfGI()*valueOfGO()) - (1.0f/3.0f));
464  std::int32_t x = static_cast<std::int32_t>(std::floor(xgd + 0.5f));
465  if((x >= 65536) || (x < 0))
466  {
467  return false;
468  }
469  GD = static_cast<std::uint16_t>(x);
470  return true;
471  }
472 
473  bool setbeta(float b)
474  {
475  float yco = b / (alpha() * valueOfCOR());
476  std::uint8_t y = value2regvco(yco);
477  // now we compute the fine adjustment
478  float zco = ( regvco2value(y) * valueOfCOR() + 0.5f*static_cast<float>(VREF)/valueOfGI() - b/alpha() ) / ( (static_cast<float>(VREF)/65536.0f)/valueOfGI() );
479  std::int32_t z = static_cast<std::int32_t>(std::floor(zco + 0.5f));
480  if((z >= 65536) || (z < 0))
481  {
482  return false;
483  }
484  Vcoarseoffset = y;
485  Vzerodac = static_cast<std::uint16_t>(z);
486 
487  return true;
488  }
489 
490  };
491 
493 
494 #endif // #if defined(IMPORT_CODE_FROM_EMBOT_HW_PGA308)
495 
496 
497  // data in here;
499  {
500 
501  }
503  {
504 
505  }
506 
507 
508  bool load(const DiscreteGain g)
509  {
510  //LUCA
511  // offset all equal to 32k-1
512  static const uint8_t _cfgmap[static_cast<uint8_t>(DiscreteGain::maxnumberof)][6] =
513  {
514  {0x00, 0x80, 0x66, 0x06, 0xcb, 0x80}, // gain = 256
515  {0x00, 0x80, 0x56, 0x0c, 0xcb, 0x80}, // gain = 128
516  {0x00, 0x40, 0x56, 0x10, 0x0f, 0x81}, // gain = 96
517  {0x00, 0x80, 0x46, 0x17, 0x6d, 0x7f}, // gain = 64
518  {0x00, 0x40, 0x46, 0x1f, 0xb1, 0x7f}, // gain = 48
519  {0x00, 0x10, 0x46, 0x2a, 0x80, 0x80}, // gain = 36
520  {0x00, 0x40, 0x42, 0x3e, 0x62, 0x7f}, // gain = 24 [or 0x26 instead of 0x42]
521  {0x00, 0x20, 0x42, 0x4b, 0x15, 0x80}, // gain = 20 [or 0x26 instead of 0x42]
522  {0x00, 0x00, 0x42, 0x5e, 0x72, 0x80}, // gain = 16 [or 0x26 instead of 0x42]
523  {0x00, 0xC0, 0x02, 0x64, 0xf6, 0x6e}, // gain = 10 [or 0x10 instead of 0x02]
524  {0x00, 0x80, 0x02, 0x64, 0x29, 0x62}, // gain = 08 [or 0x10 instead of 0x02]
525  {0x00, 0x40, 0x02, 0x64, 0xd4, 0x4c}, // gain = 06 [or 0x10 instead of 0x02]
526  {0x00, 0x40, 0x00, 0x64, 0x29, 0x22} // gain = 04
527  };
528 
529  bool ret = true;
530  switch(g)
531  {
532  case DiscreteGain::none:
533  case DiscreteGain::maxnumberof:
534  {
535  ret = false;
536  } break;
537 
538  default:
539  {
540  uint8_t index = static_cast<uint8_t>(g);
541  Registers cfg;
542  cfg.load(_cfgmap[index], 6);
543  tsf.load(cfg);
544  } break;
545 
546  }
547 
548  return ret;
549  }
550 
551  bool load_step1(const DiscreteGain g)
552  {
553  //LUCA
554  // offset are not meaningful yet. we just need zdac to be 0x8000 and cfg0.os = ... boh: 0x20
555  static const uint8_t _cfgmap[static_cast<uint8_t>(DiscreteGain::maxnumberof)][6] =
556  {
557  {0x00, 0x80, 0x66, 0x20, 0x00, 0x80}, // gain = 256
558  {0x00, 0x80, 0x56, 0x20, 0x00, 0x80}, // gain = 128
559  {0x00, 0x40, 0x56, 0x20, 0x00, 0x80}, // gain = 96
560  {0x00, 0x80, 0x46, 0x20, 0x00, 0x80}, // gain = 64
561  {0x00, 0x40, 0x46, 0x20, 0x00, 0x80}, // gain = 48
562  {0x00, 0x10, 0x46, 0x20, 0x00, 0x80}, // gain = 36
563  {0x00, 0x40, 0x42, 0x20, 0x00, 0x80}, // gain = 24 [or 0x26 instead of 0x42]
564  {0x00, 0x20, 0x42, 0x20, 0x00, 0x80}, // gain = 20 [or 0x26 instead of 0x42]
565  {0x00, 0x00, 0x42, 0x20, 0x00, 0x80}, // gain = 16 [or 0x26 instead of 0x42]
566  {0x00, 0xC0, 0x02, 0x20, 0x00, 0x80}, // gain = 10 [or 0x10 instead of 0x02]
567  {0x00, 0x80, 0x02, 0x20, 0x00, 0x80}, // gain = 08 [or 0x10 instead of 0x02]
568  {0x00, 0x40, 0x02, 0x20, 0x00, 0x80}, // gain = 06 [or 0x10 instead of 0x02]
569  {0x00, 0x40, 0x00, 0x20, 0x00, 0x80} // gain = 04
570  };
571 
572  bool ret = true;
573  switch(g)
574  {
575  case DiscreteGain::none:
576  case DiscreteGain::maxnumberof:
577  {
578  ret = false;
579  } break;
580 
581  default:
582  {
583  uint8_t index = static_cast<uint8_t>(g);
584  Registers cfg;
585  cfg.load(_cfgmap[index], 6);
586  tsf.load(cfg);
587  } break;
588 
589  }
590 
591  return ret;
592  }
593 
594  bool load(const DiscreteGain g, const Offset offset)
595  {
596  // there are some compinations of g+offset which cannot reached.
597  // if g is 6 and o8k > 7780 (ofsfet =
598  // if g is 4 and o8k > 5100 (offset =
599  if(((g == DiscreteGain::val06) && (offset > (62240))) || ((g == DiscreteGain::val04) && (offset > (40800))))
600  {
601  return false;
602  }
603 
604  // step1: we load the gain, so that we surely have some registers which are already ok.
605  // also we wnat zdac to be 0x8000
606  if(false == load_step1(g))
607  {
608  return false;
609  }
610 
611  bool ret = true;
612 
613  float o8k = offset / 8;
614 
615  // step2: we keep the values of the gain(s), and if ZDAC = 0x8000 we can compute cfg0.os in a simple mode:
616  // cfg0.os = o8k/(alpha()*valueOfCOR())
617  float cfg0os = o8k/(tsf.alpha()*tsf.valueOfCOR());
618 
619  // however, we must be sure that what we load is in range [-100, =100] and is in format sign-value.
620  int8_t Y = tsf.value2regvco(cfg0os);
621  // ok, we assign it.
622  tsf.Vcoarseoffset = Y;
623 
624  // but now we must compute the zdac with formula:
625 
626  // zdac = (64*1024)/(VREF) * ( (VREF/2) - (o8k - alpha() * valueOfCoarseOffset())/(g0*gd) )
627 
628  float z = ((64.0f*1024.0f)/tsf.VREF) * ( (tsf.VREF/2) - (o8k - tsf.alpha()*tsf.valueOfCoarseOffset())/(tsf.valueOfGO()*tsf.valueOfGD()) );
629 
630  if((z > 65535.0f) || (z < 0.0f))
631  {
632  return false;
633  }
634 
635  uint16_t Z = static_cast<std::uint16_t>(std::floor(z + 0.5f));
636  tsf.Vzerodac = Z;
637 
638  return true;
639  }
640 
641  bool get(Gain &gain, Offset &offset)
642  {
643  // this funtion extends / uses the struct TransferFunctionConfig
644  gain = tsf.alpha();
645  int32_t tmp = static_cast<int32_t>(round(8.0f*tsf.beta()));
646  if((tmp >= 0) && (tmp < 65536))
647  {
648  offset = static_cast<uint16_t>(tmp);
649  return true;
650  }
651  return false;
652  }
653 
654 
655 };
656 
657 
658 // --------------------------------------------------------------------------------------------------------------------
659 // - all the rest
660 // --------------------------------------------------------------------------------------------------------------------
661 
662 
663 
664 
665 namespace strain { namespace amplifier {
666 
667  //LUCA
668  static const float mapofgains[static_cast<uint8_t>(DiscreteGain::maxnumberof)] =
669  {
670  256,128,96,64,48, 36, 24, 20, 16, 10, 8, 6, 4
671  };
672 
674  {
675  uint8_t index = static_cast<uint8_t>(dg);
676  if(index >= static_cast<uint8_t>(DiscreteGain::maxnumberof))
677  {
678  return 0;
679  }
680  return mapofgains[index];
681  }
682 
683  bool convert(const Gain g, DiscreteGain &dg)
684  {
685  bool ret = false;
686  dg = DiscreteGain::none;
687 
688  // if g one of the allowed? i check by iteration
689  for(int i=0; i<static_cast<uint8_t>(DiscreteGain::maxnumberof); i++)
690  {
691  if(g == mapofgains[i])
692  {
693  dg = static_cast<DiscreteGain>(i);
694  ret = true;
695  break;
696  }
697  }
698 
699  return ret;
700  }
701 
702  bool convert(const WideParams &wp, DiscreteParams &dp)
703  {
704  DiscreteGain dg = DiscreteGain::none;
705  if(false == convert(wp.g, dg))
706  {
707  return false;
708  }
709  dp.dg = dg;
710  dp.o = wp.o;
711 
712  return true;
713  }
714 
715 
716  const std::uint8_t PGA308::Registers::defval[PGA308::Registers::sizeofregisters] = {0x00, 0x40, 0x46, 0x1f, 0xb1, 0x7f}; // gain = 48, offset = midrangeOffset
717 
718  bool PGA308::Registers::load(const void *data, const size_t size)
719  {
720  if((nullptr == data) || (size != sizeofregisters))
721  {
722  GD = GI = S = GO = Voffsetcoarse = Vzerodac = 0;
723  return false;
724  }
725  const uint16_t *u16 = reinterpret_cast<const uint16_t*>(data);
726  const uint8_t *u08 = reinterpret_cast<const uint8_t*>(data);
727  GD = u16[0]; Vzerodac = u16[2];
728  GI = (u08[2] >> 4) & 0x0f;
729  S = (u08[2] >> 3) & 0x01;
730  GO = (u08[2]) & 0x07;
731  Voffsetcoarse = u08[3];
732  return true;
733  }
734 
735  bool PGA308::Registers::fill(void *data, size_t &size)
736  {
737  if(nullptr == data)
738  {
739  return false;
740  }
741  uint16_t *u16 = reinterpret_cast<uint16_t*>(data);
742  uint8_t *u08 = reinterpret_cast<uint8_t*>(data);
743  u16[0] = GD; u16[2] = Vzerodac;
744  u08[2] = 0;
745  u08[2] = ((static_cast<uint8_t>(GI) & 0x0f) << 4) | ((static_cast<uint8_t>(S) & 0x01) << 3) | ((static_cast<uint8_t>(GO) & 0x07));
746  u08[3] = Voffsetcoarse;
747  size = sizeofregisters;
748  return true;
749  }
750 
751 
752  // struct basicRegs
753  // {
754  // std::uint16_t GD; // it is a gain register
755  // std::uint8_t GI : 4; // it is a gain register
756  // std::uint8_t S : 1; // it is a sign of gain register (keep it always 0)
757  // std::uint8_t GO : 3; // it is a gain register
758  // std::uint8_t Voffsetcoarse; // it is an offset register
759  // std::uint16_t Vzerodac; // it is an offset register
760 
761  // basicRegs() : GD(0), GI(0), S(0), GO(0), Voffsetcoarse(0), Vzerodac(0) {}
762  // basicRegs(void *data, size_t s) { load(data, s); }
763  // void load(const void *data, const size_t s); // import from a can frame
764  // bool fill(void *data, size_t &s); // export to a can frame
765  // };
766 
767 // void PGA308::basicRegs::load(const void *data, const size_t s)
768 // {
769 // if(nullptr == data) { GD = GI = S = GO = Voffsetcoarse = Vzerodac = 0; return; }
770 // const uint16_t *u16 = reinterpret_cast<const uint16_t*>(data);
771 // const uint8_t *u08 = reinterpret_cast<const uint8_t*>(data);
772 // GD = u16[0]; Vzerodac = u16[2];
773 // GI = (u08[2] >> 4) & 0x0f;
774 // S = (u08[2] >> 3) & 0x01;
775 // GO = (u08[2]) & 0x07;
776 // Voffsetcoarse = u08[3];
777 // }
778 
779 // bool PGA308::basicRegs::fill(void *data, size_t &s)
780 // {
781 // if(nullptr == data)
782 // {
783 // return false;
784 // }
785 // uint16_t *u16 = reinterpret_cast<uint16_t*>(data);
786 // uint8_t *u08 = reinterpret_cast<uint8_t*>(data);
787 // u16[0] = GD; u16[2] = Vzerodac;
788 // u08[2] = 0;
789 // u08[2] = ((static_cast<uint8_t>(GI) & 0x0f) << 4) | ((static_cast<uint8_t>(S) & 0x01) << 3) | ((static_cast<uint8_t>(GO) & 0x07));
790 // u08[3] = Voffsetcoarse;
791 // s = 6;
792 // return true;
793 // }
794 
795 
796 
797  PGA308::PGA308()
798  : pImpl(new Impl)
799  {
800 
801  }
802 
804  {
805  delete pImpl;
806  }
807 
808  bool PGA308::import(const Registers &regs, WideParams *wideparams)
809  {
810  load(regs);
811 
812  if(nullptr != wideparams)
813  {
814  get(wideparams->g, wideparams->o);
815  }
816 
817  return true;
818  }
819 
820  bool PGA308::import(const DiscreteParams &params, Registers *regs)
821  {
822  load(params);
823 
824  if(nullptr != regs)
825  {
826  get(*regs);
827  }
828 
829  return true;
830  }
831 
832 
833 
834  bool PGA308::load(const Registers &regs)
835  {
836  pImpl->tsf.load(regs);
837  return true;
838  }
839 
840  // attempts to load into the PGA308 a pair discretegain-offset, which produce a given Registers.
841  bool PGA308::load(const DiscreteGain g, const Offset offset)
842  {
843  if(midrangeOffset == offset)
844  {
845  return pImpl->load(g);
846  }
847 
848  return pImpl->load(g, offset);
849  }
850 
851  bool PGA308::load(const DiscreteParams &discreteparams)
852  {
853  return load(discreteparams.dg, discreteparams.o);
854  }
855 
856  // retrieve the pair gain-offset which is effectively in use after a load operation
858  {
859  return pImpl->get(gain, offset);
860  }
861 
862  bool PGA308::get(WideParams &wideparams)
863  {
864  return get(wideparams.g, wideparams.o);
865  }
866 
867 // bool PGA308::get(Params &params)
868 // {
869 // return get(params.g, params.o);
870 // }
871 
872  // retrieve the registers effectively in use.
873  bool PGA308::get(Registers &regs)
874  {
875  pImpl->tsf.get(regs);
876  return true;
877  }
878 
879 
880 
881 }} // namespace strain { namespace amplifier {
882 
883 
884 
885 // --------------------------------------------------------------------------------------------------------------------
886 // - test code
887 // --------------------------------------------------------------------------------------------------------------------
888 
889 namespace strain { namespace amplifier {
890 
891  // example of use.
892  // we must have an array of 6 PGA308 objects
893  // in the widget of the firmwareupdater:strainwindow we retrieve for each channel of the strain2 two values: a gain and an offset.
894  // we must have a
895 
897  {
898  uint8_t data[6];
899  Example_strain2_ampl_regs_t() { data[0] = data[1] = data[2] = data[3] = data[4] = data[5] = 0; }
900  void load(void *mem) { memmove(data, mem, sizeof(data)); }
901  void * memory() { return data; }
902  size_t size() { return 6; }
903  };
904 
905 
906  void testIT(std::string &output)
907  {
908 
909  const bool step1 = true;
910 
911  const bool step2 = true;
912 
913  // we use service object pga just to convert from and to.
914  PGA308 pga;
915 
917 
918  if(true == step1)
919  {
920  // in here we get two values of gain+offset (e.g., from the gui), we load int the pga and we retrieve the registers to send to the board
921  WideParams wp;
922  DiscreteParams dp;
923  PGA308::Registers regs;
924 
925 
926  wp.load(4.0, 32*1024);
927  if(true == convert(wp, dp))
928  {
929  // load dp and ...
930  //PGA308::Registers regs;
931  pga.import(dp, &regs);
932  // use the regs for instance by sending to a strain2_ampl_regs_t which can be initted from a void *
933  //Example_strain2_ampl_regs_t regstoTX;
934  size_t s;
935  regs.fill(regstoTX.memory(), s);
936  // now call
937  //cDownloader::strain_set_amplifier_regs(bus, id, regstoTX, strain_regset_inuse);
938  }
939 
940  //wp.load(48.0, 32*1024);
941  wp.load(48.0, 32531);
942  if(true == convert(wp, dp))
943  {
944  // load dp and ...
945  //PGA308::Registers regs;
946  pga.import(dp, &regs);
947  // use the regs for instance by sending to a strain2_ampl_regs_t which can be initted from a void *
948  //Example_strain2_ampl_regs_t regstoTX;
949  size_t s;
950  regs.fill(regstoTX.memory(), s);
951  // now call
952  //cDownloader::strain_set_amplifier_regs(bus, id, regstoTX, strain_regset_inuse);
953  }
954  output += "step1: ";
955  output += "done!";
956 
957  }
958 
960 
961  if(true == step2)
962  {
963  // in here we retrieve a register. and we compute the associated gain-offset
964 
965  RXregs = regstoTX;
966 
967  //cDownloader::strain_get_amplifier_regs(bus, id, RXregs, strain_regset_inuse);
968 
969  PGA308::Registers regs;
970  regs.load(RXregs.memory(), RXregs.size());
971 
972  // now regs has the content of what we have received from can bus
973  WideParams wparams;
974  pga.import(regs, &wparams);
975  // now we see if the wparams.g is one of the allowed
976  DiscreteParams dparams;
977  if(true == convert(wparams, dparams))
978  {
979  // use dparams
980  Gain gg = convert(dparams.dg);
981  Offset oo = dparams.o;
982  }
983  }
984 
985  }
986 
987  void exampleofuse(void)
988  {
989 
990 #if 1
991 
992  // we use service object pga just to convert from and to.
993  PGA308 pga;
994 
995  // in here we get two values of gain+offset (e.g., from the gui), we load int the pga and we retrieve the registers to send to the board
996  WideParams wp;
997  wp.load(48.0, 32*1024);
998  DiscreteParams dp;
999  if(true == convert(wp, dp))
1000  {
1001  // load dp and ...
1002  PGA308::Registers regs;
1003  pga.import(dp, &regs);
1004  // use the regs for instance by sending to a strain2_ampl_regs_t which can be initted from a void *
1005  Example_strain2_ampl_regs_t regstoTX;
1006  size_t s;
1007  regs.fill(regstoTX.memory(), s);
1008  // now call
1009  //cDownloader::strain_set_amplifier_regs(bus, id, regstoTX, strain_regset_inuse);
1010  }
1011 
1012  // in here we retrieve a register. and we compute the associated gain-offset
1013 
1015 
1016  //cDownloader::strain_get_amplifier_regs(bus, id, RXregs, strain_regset_inuse);
1017 
1018  PGA308::Registers regs;
1019  regs.load(RXregs.memory(), RXregs.size());
1020 
1021  // now regs has the content of what we have received from can bus
1022  WideParams wparams;
1023  pga.import(regs, &wparams);
1024  // now we see if the wparams.g is one of the allowed
1025  DiscreteParams dparams;
1026  if(true == convert(wparams, dparams))
1027  {
1028  // use dparams
1029  Gain gg = convert(dp.dg);
1030  Offset oo = dp.o;
1031  }
1032 
1033 
1034 
1035 #else
1036  // we have one for each channel
1037  PGA308 thePGAs[6];
1038 
1039  // channel 0:
1040  DiscreteParams discreteparams;
1041  // get the value from teh widget
1042  discreteparams.load(DiscreteGain::val10, 32000);
1043  // load them into the object
1044  thePGAs[0].load(discreteparams);
1045  // now i want to send the packet to the board. i retrieve teh registers .
1046  PGA308::Registers regs;
1047  thePGAs[0].get(regs);
1048  // and now i transform them into a payload for can tx
1049  uint8_t payload[8] = {0};
1050  regs.fill(payload);
1051  // and now i use payload to tx.
1052 
1053  // now i ask the registers to the board. i receive a payload
1054  uint8_t rxpayload[8] = {0}; // ok, not zero but ...
1055  regs.load(rxpayload);
1056  // and i want to fill the widget with the real values
1057  PGA308::Registers rxregs;
1058  rxregs.load(rxpayload);
1059  float gg =0;
1060  uint16_t oo =0;
1061  thePGAs[0].load(rxregs);
1062  thePGAs[0].get(gg, oo);
1063  // print gg, oo
1064 #endif
1065 
1066  }
1067 
1068 
1069 }} // namespace strain { namespace amplifier
1070 
1071 
1072 
1073 namespace strain { namespace dsp { namespace fsc {
1074 
1075  FSC convert(const double v, bool &saturated)
1076  {
1077  saturated = false;
1078  FSC ret = static_cast<FSC>(v);
1079 
1080  if(v>fsc::max)
1081  {
1082  saturated = true;
1083  ret = fsc::max;
1084  }
1085 
1086  if(v<fsc::min)
1087  {
1088  saturated = true;
1089  ret = fsc::min;
1090  }
1091 
1092  return ret;
1093  }
1094 
1095  double convert(const FSC v)
1096  {
1097  return static_cast<double>(v);
1098  }
1099 
1100 
1101  bool convert(const std::vector<double> &in, std::vector<FSC> &out)
1102  {
1103  bool sat = false;
1104  bool ret = true;
1105  out.resize(0);
1106  for(int i=0; i<in.size(); i++)
1107  {
1108  out.push_back(strain::dsp::fsc::convert(in[i], sat));
1109  if(sat)
1110  {
1111  ret = false;
1112  }
1113  }
1114  return ret;
1115  }
1116 
1117  bool convert(const std::vector<FSC> &in, std::vector<double> &out)
1118  {
1119  bool ret = true;
1120  out.resize(0);
1121  for(int i=0; i<in.size(); i++)
1122  {
1123  out.push_back(strain::dsp::fsc::convert(in[i]));
1124  }
1125  return ret;
1126  }
1127 
1128 
1129 } } } // namespace strain { namespace dsp { namespace fsc {
1130 
1131 
1132 
1133 namespace strain { namespace dsp { namespace q15 {
1134 
1135  Q15 convert(const double v, bool &saturated)
1136  {
1137  Q15result rr = static_cast<Q15result>(v * 32768.0); // note: 32768.0 = 2^15
1138  return saturate(rr, saturated);
1139  }
1140 
1141  Q15 U16toQ15(const std::uint16_t valU16)
1142  {
1143  return valU16-0x8000;
1144  }
1145 
1146  bool convert(const std::vector<double> &in, std::vector<Q15> &out)
1147  {
1148  bool sat = false;
1149  bool ret = true;
1150  out.resize(0);
1151  for(int i=0; i<in.size(); i++)
1152  {
1153  out.push_back(convert(in[i], sat));
1154  if(sat)
1155  {
1156  ret = false;
1157  }
1158  }
1159  return ret;
1160  }
1161 
1162  bool convert(const std::vector<Q15> &in, std::vector<double> &out)
1163  {
1164  bool ret = true;
1165  out.resize(0);
1166  for(int i=0; i<in.size(); i++)
1167  {
1168  out.push_back(convert(in[i]));
1169  }
1170  return ret;
1171  }
1172 
1173  std::uint16_t Q15toU16(const Q15 valQ15)
1174  {
1175  return valQ15+0x8000;
1176  }
1177 
1178  double convert(const Q15 v)
1179  {
1180  return static_cast<double>(v) / 32768.0; // note: 32768.0 = 2^15
1181  }
1182 
1183  Q15 opposite(const Q15 v)
1184  {
1185  if(negOne == v)
1186  {
1187  return posOneNearly;
1188  }
1189  return -v;
1190  }
1191 
1192  Q15 saturate(const Q15result x, bool &saturated)
1193  {
1194  if (x > 0x7FFF)
1195  {
1196  saturated = true;
1197  return 0x7FFF;
1198  }
1199  else if (x < -0x8000)
1200  {
1201  saturated = true;
1202  return -0x8000;
1203  }
1204 
1205  saturated = false;
1206  return static_cast<Q15>(x);
1207  }
1208 
1209  Q15 add(const Q15 a, const Q15 b)
1210  {
1211  bool saturated = false;
1212  return add(a, b, saturated);
1213  }
1214 
1215  Q15 add(const Q15 a, const Q15 b, bool &saturated)
1216  {
1217  Q15result tmp = static_cast<Q15result>(a) + static_cast<Q15result>(b);
1218 
1219  return saturate(tmp, saturated);
1220  }
1221 
1222  Q15 sub(Q15 &a, Q15 &b)
1223  {
1224  return a-b;
1225  }
1226 
1227  Q15 mul(const Q15 a, const Q15 b, bool &saturated)
1228  {
1229  Q15result tmp = static_cast<Q15result>(a) * static_cast<Q15result>(b);
1230 
1231  // Rounding; mid values are rounded up
1232  tmp += (1 << (15 - 1));
1233  // Correct by dividing by base
1234  tmp >>= 15;
1235  // and saturate result
1236  return saturate(tmp, saturated);
1237  }
1238 
1239  Q15 mul(const Q15 a, const Q15 b)
1240  {
1241  bool saturated = false;
1242  return mul(a, b, saturated);
1243  }
1244 
1245  Q15 div(const Q15 a, const Q15 b, bool &saturated)
1246  {
1247  Q15result n1 = static_cast<Q15result>(a);
1248  Q15result n2 = static_cast<Q15result>(b);
1249  Q15result rr = 0;
1250  std::uint8_t neg = 0;
1251 
1252  if(0 == n2)
1253  {
1254  saturated = true;
1255  return 0;
1256  }
1257 
1258  if(n1 < 0)
1259  {
1260  neg = !neg;
1261  n1 = -n1;
1262  }
1263 
1264  if(n2 < 0)
1265  {
1266  neg = !neg;
1267  n2 = -n2;
1268  }
1269 
1270  rr = (n1 << 15) / n2;
1271 
1272  if(0 != neg)
1273  {
1274  rr = - rr;
1275  }
1276 
1277  return saturate(rr, saturated);
1278  }
1279 
1280  bool add(const matrix &m1, const matrix &m2, matrix &res, bool &saturated)
1281  {
1282  if((m1.ncols != m2.ncols) || (m1.ncols != res.ncols))
1283  {
1284  return false;
1285  }
1286  if((m1.nrows != m2.nrows) || (m1.nrows != res.nrows))
1287  {
1288  return false;
1289  }
1290 
1291  saturated = false;
1292 
1293  // ok, we do action
1294  for(int r=0; r<res.nrows; r++)
1295  {
1296  for(int c=0; c<res.ncols; c++)
1297  {
1298  bool sat1 = false;
1299  res.data[r*res.ncols+c] = add(m1.data[r*m1.ncols+c], m2.data[r*m2.ncols+c], sat1);
1300 
1301  if(sat1)
1302  {
1303  saturated = true;
1304  }
1305  }
1306  }
1307 
1308  return true;
1309  }
1310 
1311  bool multiply(const matrix &m1, const matrix &m2, matrix &res, bool &saturated)
1312  {
1313  if(m1.ncols != m2.nrows)
1314  {
1315  return false;
1316  }
1317 
1318  if(m1.nrows != res.nrows)
1319  {
1320  return false;
1321  }
1322 
1323  if(m2.ncols != res.ncols)
1324  {
1325  return false;
1326  }
1327 
1328  saturated = false;
1329  std::uint32_t nsat = 0;
1330 
1331  // ok, we do action
1332  for(int r=0; r<res.nrows; r++)
1333  {
1334  for(int c=0; c<res.ncols; c++)
1335  {
1336  Q15 v = 0;
1337 
1338  const Q15 *row_wise = &m1.data[r*m1.ncols]; // navigo con +1
1339  const Q15 *col_wise = &m2.data[c]; // navigo con +(m2.ncols)
1340  for(int i=0; i<m1.ncols; i++)
1341  {
1342  bool sat1 = false;
1343  bool sat2 = false;
1344  Q15 x = mul(*row_wise, *col_wise, sat1);
1345  v = add(v, x, sat2);
1346  if(sat1 || sat2)
1347  {
1348  nsat ++;
1349  saturated = true;
1350  }
1351  row_wise += 1;
1352  col_wise += m2.ncols;
1353  }
1354 
1355  res.data[c + r*res.ncols] = v;
1356  }
1357  }
1358 
1359  return true;
1360  }
1361 
1362 } } } // namespace strain { namespace dsp { namespace q15 {
1363 
1364 namespace strain { namespace regulation {
1365 
1366  bool read(const std::string fname, FullRegulation &reg)
1367  {
1368  bool ret = false;
1369 #if 0
1370  // to be done later on
1371 
1372  reg.clear();
1373 
1374  if(fname.empty())
1375  {
1376 // yError("File not found!\n");
1377 // appendLogMsg("File not found!");
1378  return false;
1379  }
1380 
1381 // if (selected_id <1 || selected_id >= 15){
1382 // yError("Invalid board address!\n");
1383 // appendLogMsg("Invalid board address!");
1384 // return false;
1385 // }
1386 
1387  const char * filename = fname.c_str();
1388  int file_version=0;
1389  std::fstream filestr;
1390  filestr.open (filename, fstream::in);
1391  if (!filestr.is_open()){
1392 // yError("Error opening calibration file!\n");
1393 // appendLogMsg("Error opening calibration file!");
1394  return false;
1395  }
1396 
1397  int i=0;
1398  char buffer[256];
1399 
1400  //file version
1401  filestr.getline (buffer,256);
1402  filestr.getline (buffer,256);
1403  sscanf (buffer,"%d",&file_version);
1404 
1405 
1406  if((4 != file_version) && (3 != file_version))
1407  {
1408 // yError("Wrong file. Calibration version not supported for strain2: %d\n", file_version);
1409 // appendLogMsg("Wrong file. Calibration version not supported for strain2");
1410  return false;
1411  }
1412 
1413  reg.version = static_cast<Version>(file_version);
1414 
1415  if(Version::three == reg.version)
1416  {
1417  // Board type:
1418  filestr.getline (buffer,256);
1419  filestr.getline (buffer,256);
1420  if(0 != strcmp(buffer, "strain2"))
1421  {
1422 // yError("Wrong file. Board type not supported: %s\n", buffer);
1423 // appendLogMsg("Wrong file. Board type not supported");
1424  return false;
1425  }
1426 
1427  reg.board = Board::strain2;
1428 
1429  // Serial number:
1430  char serial_no[256] = {0};
1431  filestr.getline (buffer,256);
1432  filestr.getline (buffer,256);
1433  snprintf(serial_no, sizeof(serial_no), "%s", buffer);
1434  //core->getDownloader()->strain_set_serial_number(bus,id, serial_no);
1435 
1436  reg.serial = std::string(serial_no);
1437 
1438  // there is only one regulation set
1439 
1440  Set set;
1441  set.clear();
1442 
1443  // Amplifier registers:
1444  filestr.getline (buffer,256);
1445  for (i=0;i<6; i++)
1446  {
1447  filestr.getline (buffer,256);
1448 // yDebug() << buffer;
1449  unsigned int t08[6] = {0};
1450  sscanf (buffer,"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", &t08[0], &t08[1], &t08[2], &t08[3], &t08[4], &t08[5]);
1451  for(int j=0; j<6; j++)
1452  {
1453  set.analog.amplregs[i][j] = t08[j];
1454  }
1455 
1456 // core->getDownloader()->strain_set_amplifier_regs(core->getDownloader()->board_list[selected].bus, core->getDownloader()->board_list[selected].pid, i, amp_registers[i], regset);
1457 
1458  // downloader.strain_set_offset (downloader.board_list[selected].bus, downloader.board_list[selected].pid, i, offset[i]);
1459  //core->getDownloader()->strain_set_offset (bus,id, i, offset[i]);
1460  //printf("0X%02x, 0X%02x, 0X%02x, 0X%02x, 0X%02x,0X%02x", amp_registers[i].data[0], amp_registers[i].data[1], amp_registers[i].data[2], amp_registers[i].data[3], amp_registers[i].data[4], amp_registers[i].data[5]);
1461  //fflush(stdout);
1462 // drv_sleep(10);
1463  }
1464 
1465 
1466 
1467  //calibration matrix
1468  filestr.getline (buffer,256);
1469  for (i=0;i<36; i++){
1470  unsigned int tmp = 0;
1471  filestr.getline (buffer,256);
1472  sscanf (buffer,"%x", &tmp);
1473  set.digital.matrix[i] = static_cast<strain::dsp::Q15>(tmp);
1474 // core->getDownloader()->strain_set_matrix_rc(bus,id, ri, ci, calib_matrix[index][ri][ci], regset);
1475  }
1476 
1477 
1478 
1479  //matrix gain
1480  filestr.getline (buffer,256);
1481  filestr.getline (buffer,256);
1482  int cc=0;
1483  sscanf (buffer,"%d",&cc);
1484 // core->getDownloader()->strain_set_matrix_gain(bus,id, cc, regset);
1485 
1486  //tare
1487  filestr.getline (buffer,256);
1488  for (i=0;i<6; i++){
1489  filestr.getline (buffer,256);
1490  int tt = 0;
1491  sscanf (buffer,"%d", &tt);
1492  set.digital.tare[i] = static_cast<std::uint16_t>(tt);
1493 // core->getDownloader()->strain_set_calib_bias(bus,id, i, calib_bias[i], regset);
1494  }
1495 
1496  //full scale values
1497  filestr.getline (buffer,256);
1498  for (i=0;i<6; i++){
1499  filestr.getline (buffer,256);
1500  int fs = 0;
1501  sscanf (buffer,"%d", &fs);
1502  set.digital.fullscale[i] = static_cast<strain::dsp::FSC>(fs);
1503 // core->getDownloader()->strain_set_full_scale(bus,id, i, full_scale_const[index][i], regset);
1504  }
1505 
1506  reg.sets.push_back(set);
1507 
1508  }
1509 
1510  reg.set2useatbootstrap = 1;
1511 
1512 
1513  filestr.close();
1514  filestr.clear();
1515 
1516 #endif
1517 
1518  return ret;
1519  }
1520 
1521 } } // namespace strain { namespace regulation
1522 
1523 
1524 // - end-of-file (leave a blank line after)----------------------------------------------------------------------------
1525 
@ data
virtual bool load(const void *data, const size_t size)
Definition: strain.cpp:718
virtual bool fill(void *data, size_t &size)
Definition: strain.cpp:735
bool import(const Registers &regs, WideParams *wideparams=nullptr)
Definition: strain.cpp:808
bool load(const Registers &regs)
Definition: strain.cpp:834
bool get(WideParams &wideparams)
Definition: strain.cpp:862
double sat(const double val, const double min, const double max)
Definition: utils.h:183
void exampleofuse(void)
Definition: strain.cpp:987
Gain convert(const DiscreteGain dg)
Definition: strain.cpp:673
static const float mapofgains[static_cast< uint8_t >(DiscreteGain::maxnumberof)]
Definition: strain.cpp:668
void testIT(std::string &output)
Definition: strain.cpp:906
std::uint16_t Offset
Definition: strain.h:121
const Offset midrangeOffset
Definition: strain.h:140
FSC convert(const double v, bool &saturated)
Definition: strain.cpp:1075
const FSC max
Definition: strain.h:48
const FSC min
Definition: strain.h:49
const Q15 negOne
Definition: strain.h:61
std::uint16_t Q15toU16(const Q15 valQ15)
Definition: strain.cpp:1173
Q15 saturate(const Q15result x, bool &saturated)
Definition: strain.cpp:1192
Q15 convert(const double v, bool &saturated)
Definition: strain.cpp:1135
Q15 sub(Q15 &a, Q15 &b)
Definition: strain.cpp:1222
bool multiply(const matrix &m1, const matrix &m2, matrix &res, bool &saturated)
Definition: strain.cpp:1311
Q15 div(const Q15 a, const Q15 b, bool &saturated)
Definition: strain.cpp:1245
const Q15 posOneNearly
Definition: strain.h:72
Q15 mul(const Q15 a, const Q15 b, bool &saturated)
Definition: strain.cpp:1227
Q15 U16toQ15(const std::uint16_t valU16)
Definition: strain.cpp:1141
Q15 opposite(const Q15 v)
Definition: strain.cpp:1183
double convert(const Q15 v)
Definition: strain.cpp:1178
Q15 add(const Q15 a, const Q15 b)
Definition: strain.cpp:1209
std::uint16_t FSC
Definition: strain.h:40
std::int16_t Q15
Definition: strain.h:41
std::int32_t Q15result
Definition: strain.h:42
bool read(const std::string fname, FullRegulation &reg)
Definition: strain.cpp:1366
out
Definition: sine.m:8
degrees offset
Definition: sine.m:4
void load(DiscreteGain _dg, Offset _o)
Definition: strain.h:149
CFG0register(std::uint8_t GO, std::uint8_t MUX, std::uint8_t GI, std::uint8_t OS)
Definition: strain.cpp:124
bool alignVOUT(const std::uint16_t vout, const std::uint16_t target, std::uint8_t &Y, std::uint16_t &Z)
Definition: strain.cpp:437
void assign(const CFG0register &cfg0, const ZDACregister &zdac, const GDACregister &gdac)
Definition: strain.cpp:308
void obtain(CFG0register &cfg0, ZDACregister &zdac, GDACregister &gdac) const
Definition: strain.cpp:300
void computeOffsetParams(const std::uint16_t vout, float &a, float &b, float &c)
Definition: strain.cpp:427
TransferFunctionConfig tsf
Definition: strain.cpp:492
bool load(const DiscreteGain g, const Offset offset)
Definition: strain.cpp:594
bool load_step1(const DiscreteGain g)
Definition: strain.cpp:551
bool get(Gain &gain, Offset &offset)
Definition: strain.cpp:641
bool load(const DiscreteGain g)
Definition: strain.cpp:508
void load(Gain _g, Offset _o)
Definition: strain.h:158
std::uint8_t ncols
Definition: strain.h:96
std::uint8_t nrows
Definition: strain.h:95
std::uint8_t amplregs[strain::numberofchannels][strain::amplifier::PGA308::Registers::sizeofregisters]
Definition: strain.h:272
strain::dsp::Q15 matrix[strain::numberofchannels *strain::numberofchannels]
Definition: strain.h:287
strain::dsp::FSC fullscale[strain::numberofchannels]
Definition: strain.h:288
std::uint16_t tare[strain::numberofchannels]
Definition: strain.h:286
std::vector< Set > sets
Definition: strain.h:328