DIY Logging Volt/Ampmeter
conversion.c File Reference

Conversion and settings-related methods and structs for high-precision logging voltage/current meter. More...

#include "conversion.h"
#include <stdint.h>
#include "usart.h"
#include "util.h"
#include "rtc.h"

Go to the source code of this file.

Functions

void initDataStruct (void)
 Function to initialize/reset the values in the data-struct. More...
 
void initSettingsStruct (void)
 Function to initialize/reset the values in the settings-struct. More...
 
void forceConversion (void)
 Function to force a conversion of all values not (yet) displayed on the OLED screens. More...
 
void convertValues (void)
 Function to convert the measurements to char-arrays. More...
 
void incSecondPassed (void)
 Function to increase the value of secondPassed. More...
 
uint8_t decSecondPassed (void)
 Function to decrease the value of secondPassed. More...
 

Detailed Description

Conversion and settings-related methods and structs for high-precision logging voltage/current meter.

Version
1.1
Author
Brecht Van Eeckhoudt

Versions

  • v1.0: Initial version.
  • v1.1: Changed default measurement period to 10s.

Todo:
Future improvements:
  • Check/optimize flow in convertValues.
  • Convert negative float values.
  • Add max/min power fields.

License

Copyright (C) 2021 - Brecht Van Eeckhoudt

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

A copy of the GNU General Public License can be found in the LICENSE file along with this source code.

Definition in file conversion.c.

Function Documentation

◆ convertValues()

void convertValues ( void  )

Function to convert the measurements to char-arrays.

Only updated and visible items on the OLED screens get converted.

Definition at line 172 of file conversion.c.

173 {
174  /* Fields for float splitting */
175  uint16_t beforeComma = 0;
176  uint16_t afterComma = 0;
177 
178  /* Update battery voltage if necessary */
179  if (settings.newVbat == 1)
180  {
181  splitFloat(settings.vbat, &beforeComma, &afterComma, 2);
182 
183  /* Limit values just in case */
184  if (beforeComma > 9) beforeComma = 9;
185  if (afterComma > 99) afterComma = 99;
186 
187  uint32_to_charDec(settings.vbatLeft, beforeComma, 1);
188  uint32_to_charDec(settings.vbatRight, afterComma, 2);
189 
190  settings.newVbat = 0;
191 
192  /* Indicate that the display needs to be updated */
193  settings.newCharVbat = 1;
194  }
195 
196 
197  /* Update VOLT fields if necessary */
198  if (data.newVolt)
199  {
200  splitFloat(data.voltage, &beforeComma, &afterComma, 3);
201 
202  data.newVolt = 0;
203 
204  uint32_to_charDec(cData.vLeft, beforeComma, 1);
205  uint32_to_charDec(cData.vRight, afterComma, 3);
206 
207  /* Indicate that the display needs to be updated */
208  cData.newVolt = 1;
209  }
210 
211  /* Update MIN VOLT fields if necessary */
212  if ((data.newMinVolt && (settings.leftPage == 0)) || settings.forceConv)
213  {
214  splitFloat(data.minVoltage, &beforeComma, &afterComma, 3);
215 
216  data.newMinVolt = 0;
217 
218  uint32_to_charDec(cData.vMinLeft, beforeComma, 2);
219  uint32_to_charDec(cData.vMinRight, afterComma, 3);
220 
221  /* Indicate that the display needs to be updated */
222  cData.newMinVolt = 1;
223  }
224 
225  /* Update MAX VOLT fields if necessary */
226  if ((data.newMaxVolt && (settings.leftPage == 0)) || settings.forceConv)
227  {
228  splitFloat(data.maxVoltage, &beforeComma, &afterComma, 3);
229 
230  data.newMaxVolt = 0;
231 
232  uint32_to_charDec(cData.vMaxLeft, beforeComma, 2);
233  uint32_to_charDec(cData.vMaxRight, afterComma, 3);
234 
235  /* Indicate that the display needs to be updated */
236  cData.newMaxVolt = 1;
237  }
238 
239 
240  /* Update CURR fields if necessary */
241  if (data.newCurr)
242  {
243  splitFloat(data.current, &beforeComma, &afterComma, 4);
244 
245  data.newCurr = 0;
246 
247  uint32_to_charDec(cData.aLeft, beforeComma, 1);
248  uint32_to_charDec(cData.aRight, afterComma, 4);
249 
250  /* Indicate that the display needs to be updated */
251  cData.newCurr = 1;
252  }
253 
254  /* Update MIN CURR fields if necessary */
255  if ((data.newMinCurr && (settings.leftPage == 1)) || settings.forceConv)
256  {
257  splitFloat(data.minCurrent, &beforeComma, &afterComma, 4);
258 
259  data.newMinCurr = 0;
260 
261  uint32_to_charDec(cData.aMinLeft, beforeComma, 1);
262  uint32_to_charDec(cData.aMinRight, afterComma, 4);
263 
264  /* Indicate that the display needs to be updated */
265  cData.newMinCurr = 1;
266  }
267 
268  /* Update MAX CURR fields if necessary */
269  if ((data.newMaxCurr && (settings.leftPage == 1)) || settings.forceConv)
270  {
271  splitFloat(data.maxCurrent, &beforeComma, &afterComma, 4);
272 
273  data.newMaxCurr = 0;
274 
275  uint32_to_charDec(cData.aMaxLeft, beforeComma, 1);
276  uint32_to_charDec(cData.aMaxRight, afterComma, 4);
277 
278  /* Indicate that the display needs to be updated */
279  cData.newMaxCurr = 1;
280  }
281 
282 
283  /* Update POWER fields if necessary */
284  if (data.newPow)
285  {
286  splitFloat(data.power, &beforeComma, &afterComma, 3);
287 
288  data.newPow = 0;
289 
290  uint32_to_charDec(cData.pLeft, beforeComma, 1);
291  uint32_to_charDec(cData.pRight, afterComma, 3);
292 
293  /* Indicate that the display needs to be updated */
294  cData.newPow = 1;
295  }
296 
297  /* Update Ah fields if necessary */
298  if ((data.newAh && (settings.leftPage == 2)) || settings.forceConv)
299  {
300  splitFloat(data.ah, &beforeComma, &afterComma, 3);
301 
302  data.newAh = 0;
303 
304  uint32_to_charDec(cData.ahLeft, beforeComma, 2);
305  uint32_to_charDec(cData.ahRight, afterComma, 3);
306 
307  /* Indicate that the display needs to be updated */
308  cData.newAh = 1;
309  }
310 
311  /* Update Wh fields if necessary */
312  if ((data.newWh && (settings.leftPage == 2)) || settings.forceConv)
313  {
314  splitFloat(data.wh, &beforeComma, &afterComma, 3);
315 
316  data.newWh = 0;
317 
318  uint32_to_charDec(cData.whLeft, beforeComma, 2);
319  uint32_to_charDec(cData.whRight, afterComma, 3);
320 
321  /* Indicate that the display needs to be updated */
322  cData.newWh = 1;
323  }
324 
325 
326  /* Update runtime HOUR field if necessary */
327  if (data.newRunHours)
328  {
329  data.newRunHours = 0;
330 
332 
333  /* Indicate that the display needs to be updated */
334  cData.newRunHours = 1;
335  }
336 
337  /* Update runtime MIN field if necessary */
338  if (data.newRunMins)
339  {
340  data.newRunMins = 0;
341 
343 
344  /* Indicate that the display needs to be updated */
345  cData.newRunMins = 1;
346  }
347 
348  /* Update runtime SEC field if necessary */
349  if (data.newRunSecs)
350  {
351  data.newRunSecs = 0;
352 
354 
355  /* Indicate that the display needs to be updated */
356  cData.newRunSecs = 1;
357  }
358 
359 
360  /* Update DAY field if necessary */
362  {
363  if (rtc.latest == 0) uint32_to_charDec(rtc.charDay, rtc.day0, 2);
364  else if (rtc.latest == 1) uint32_to_charDec(rtc.charDay, rtc.day1, 2);
365 
366  /* Indicate that the display needs to be updated */
367  rtc.newCharDay = 1;
368  }
369 
370  /* Update MONTH field if necessary */
372  {
374  else if (rtc.latest == 1) uint32_to_charDec(rtc.charMonth, rtc.month1, 2);
375 
376  /* Indicate that the display needs to be updated */
377  rtc.newCharMonth = 1;
378  }
379 
380  /* Update YEAR field if necessary */
382  {
384  else if (rtc.latest == 1) uint32_to_charDec(rtc.charYear, rtc.year1, 4);
385 
386  /* Indicate that the display needs to be updated */
387  rtc.newCharYear = 1;
388  }
389 
390 
391  /* Update HOUR field if necessary */
393  {
395  else if (rtc.latest == 1) uint32_to_charDec(rtc.charHour, rtc.hour1, 2);
396 
397  /* Indicate that the display needs to be updated */
398  rtc.newCharHour = 1;
399  }
400 
401  /* Update MINUTE field if necessary */
403  {
404  if (rtc.latest == 0) uint32_to_charDec(rtc.charMin, rtc.min0, 2);
405  else if (rtc.latest == 1) uint32_to_charDec(rtc.charMin, rtc.min1, 2);
406 
407  /* Indicate that the display needs to be updated */
408  rtc.newCharMin = 1;
409  }
410 
411  /* Update SECOND field if necessary */
413  {
414  if (rtc.latest == 0) uint32_to_charDec(rtc.charSec, rtc.sec0, 2);
415  else if (rtc.latest == 1) uint32_to_charDec(rtc.charSec, rtc.sec1, 2);
416 
417  settings.newSec = 0;
418 
419  /* Indicate that the display needs to be updated */
420  rtc.newCharSec = 1;
421  }
422 
423 
424  /* Reset hour/min/sec char conversion logic after startup */
425  if (rtc.firstUpdate) rtc.firstUpdate = 0;
426 }

◆ decSecondPassed()

uint8_t decSecondPassed ( void  )

Function to decrease the value of secondPassed.

Returns
  • 0 - Could not decrease, value already at zero.
  • 1 - secondPassed decreased by one.

Definition at line 447 of file conversion.c.

448 {
449  if (settings.secPassed > 0)
450  {
452  return (1);
453  }
454 
455  return (0);
456 }

◆ forceConversion()

void forceConversion ( void  )

Function to force a conversion of all values not (yet) displayed on the OLED screens.

Definition at line 155 of file conversion.c.

156 {
157  settings.forceConv = 1;
158 
159  convertValues();
160 
161  settings.forceConv = 0;
162 }

◆ incSecondPassed()

void incSecondPassed ( void  )

Function to increase the value of secondPassed.

Definition at line 433 of file conversion.c.

434 {
436 }

◆ initDataStruct()

void initDataStruct ( void  )

Function to initialize/reset the values in the data-struct.

Definition at line 69 of file conversion.c.

70 {
71  data.voltReceived = 0;
72  data.firstVolt = 1; /* Reset minVolt logic */
73  data.voltage = 0.0;
74  data.oldVolt = 0.0;
75  data.newVolt = 1; /* Force char conversion and display update */
76  data.minVoltage = 0.0;
77  data.newMinVolt = 1; /* Force char conversion and display update */
78  data.maxVoltage = 0.0;
79  data.newMaxVolt = 1; /* Force char conversion and display update */
80 
81  data.currReceived = 0;
82  data.firstCurr = 1; /* Reset minCurr logic */
83  data.current = 0.0;
84  data.oldCurr = 0.0;
85  data.newCurr = 1; /* Force char conversion and display update */
86  data.minCurrent = 0.0;
87  data.newMinCurr = 1; /* Force char conversion and display update */
88  data.maxCurrent = 0.0;
89  data.newMaxCurr = 1; /* Force char conversion and display update */
90 
91  data.power = 0.0;
92  data.oldPower = 0.0;
93  data.newPow = 1; /* Force char conversion and display update */
94 
95  data.ah = 0.0;
96  data.newAh = 1; /* Force char conversion and display update */
97  data.wh = 0.0;
98  data.newWh = 1; /* Force char conversion and display update */
99 
100  data.runHours = 0;
101  data.newRunHours = 1; /* Force char conversion and display update */
102  data.runMins = 0;
103  data.newRunMins = 1; /* Force char conversion and display update */
104  data.runSecs = 0;
105  data.newRunSecs = 1; /* Force char conversion and display update */
106 
107  settings.forceConv = 0; /* Don't convert all invisible values yet */
108 
109 // data.msCounter0 = 0;
110 // data.msCounter1 = 0;
111 // data.latestMScounter = 0;
112 }

◆ initSettingsStruct()

void initSettingsStruct ( void  )

Function to initialize/reset the values in the settings-struct.

Definition at line 119 of file conversion.c.

120 {
121  settings.selectedDisplay = 0; /* Left display selected */
122  settings.leftPage = 0; /* Left display starts on page 0 */
123  settings.rightPage = 0; /* Right display starts on page 0 */
124  settings.newSelDisplay = 1; /* Draw selection lines */
125  settings.mode = 0; /* Starting mode = STOP */
126  settings.newMode = 1; /* Force display update */
127 
128  settings.changeDateTime = 0; /* We're not changing the date/time yet */
129  settings.dateTimeChanged = 1; /* Force display update */
130  settings.changePeriod = 0; /* We're not changing the period yet */
131  settings.periodChanged = 1; /* Force display update */
132  settings.remMeasPeriodS = 0; /* Make sure we directly save the next measurement */
133  settings.measPeriodIndex = 4; /* Default index for measurement-period LUT */
134  settings.measPeriodS = 10; /* Default to 10s measurement period */
135 
136  settings.vbat = 0.0; /* Reset battery voltage */
137  settings.vbatCounter = 0; /* Check battery voltage on startup */
138  settings.newCharVbat = 1; /* Force display update */
139 
140  settings.secPassed = 0; /* Reset value for second interrupt signaling */
141  settings.headerSaved = 0; /* UART logger not yet initialized */
142  settings.oldTIM3 = 0; /* Reset value for encoder logic */
143  settings.newSec = 1; /* Force display update */
144  settings.loopAsDelay = 0; /* We're not doing additional loops on startup */
145  settings.loggerReady = 0; /* UART logger not yet started up */
146  settings.msWaiting = 0; /* Reset waiting-time functionality */
147  settings.msWaitingStart = 0; /* Reset waiting-time functionality */
148 }
Settings_t::headerSaved
uint8_t headerSaved
Definition: conversion.h:161
Settings_t::loopAsDelay
uint8_t loopAsDelay
Definition: conversion.h:166
Data_t::runSecs
uint8_t runSecs
Definition: conversion.h:85
cData_t::newCurr
uint8_t newCurr
Definition: conversion.h:108
RTC_dateTime_t::hour0
uint8_t hour0
Definition: rtc.h:55
Settings_t::rightPage
uint8_t rightPage
Definition: conversion.h:151
Settings_t::selectedDisplay
uint8_t selectedDisplay
Definition: conversion.h:148
Data_t::oldVolt
float oldVolt
Definition: conversion.h:55
settings
struct Settings_t settings
Data_t::current
float current
Definition: conversion.h:64
cData_t::aMaxLeft
char aMaxLeft[2]
Definition: conversion.h:109
cData_t::aMaxRight
char aMaxRight[5]
Definition: conversion.h:110
RTC_dateTime_t::min1
uint8_t min1
Definition: rtc.h:61
cData_t::newMaxCurr
uint8_t newMaxCurr
Definition: conversion.h:111
cData_t::newRunHours
uint8_t newRunHours
Definition: conversion.h:128
Settings_t::msWaiting
uint16_t msWaiting
Definition: conversion.h:168
Data_t::newRunHours
uint8_t newRunHours
Definition: conversion.h:82
cData_t::ahLeft
char ahLeft[5]
Definition: conversion.h:120
Settings_t::leftPage
uint8_t leftPage
Definition: conversion.h:150
Data_t::newMaxVolt
uint8_t newMaxVolt
Definition: conversion.h:61
cData_t::newPow
uint8_t newPow
Definition: conversion.h:118
Data_t::maxCurrent
float maxCurrent
Definition: conversion.h:70
Data_t::maxVoltage
float maxVoltage
Definition: conversion.h:60
Data_t::newAh
uint8_t newAh
Definition: conversion.h:77
rtc
struct RTC_dateTime_t rtc
cData_t::charRunHours
char charRunHours[3]
Definition: conversion.h:127
Data_t::runHours
uint8_t runHours
Definition: conversion.h:81
cData_t::aRight
char aRight[5]
Definition: conversion.h:107
cData
struct cData_t cData
RTC_dateTime_t::newCharMonth
uint8_t newCharMonth
Definition: rtc.h:80
Data_t::newRunSecs
uint8_t newRunSecs
Definition: conversion.h:86
data
struct Data_t data
RTC_dateTime_t::charMonth
char charMonth[3]
Definition: rtc.h:79
RTC_dateTime_t::charHour
char charHour[3]
Definition: rtc.h:57
Settings_t::loggerReady
volatile uint8_t loggerReady
Definition: conversion.h:167
RTC_dateTime_t::year0
uint16_t year0
Definition: rtc.h:82
Data_t::wh
float wh
Definition: conversion.h:78
Settings_t::changePeriod
uint8_t changePeriod
Definition: conversion.h:156
Data_t::newMinVolt
uint8_t newMinVolt
Definition: conversion.h:59
Data_t::currReceived
uint8_t currReceived
Definition: conversion.h:63
cData_t::vLeft
char vLeft[3]
Definition: conversion.h:96
Settings_t::newMode
uint8_t newMode
Definition: conversion.h:147
cData_t::whLeft
char whLeft[5]
Definition: conversion.h:123
RTC_dateTime_t::newCharMin
uint8_t newCharMin
Definition: rtc.h:63
cData_t::whRight
char whRight[4]
Definition: conversion.h:124
RTC_dateTime_t::charSec
char charSec[3]
Definition: rtc.h:67
RTC_dateTime_t::charDay
char charDay[3]
Definition: rtc.h:72
cData_t::pLeft
char pLeft[4]
Definition: conversion.h:116
cData_t::charRunMins
char charRunMins[3]
Definition: conversion.h:129
cData_t::pRight
char pRight[4]
Definition: conversion.h:117
splitFloat
void splitFloat(float fValue, uint16_t *beforeComma, uint16_t *afterComma, uint8_t decimalPlaces)
Split a float value in two uint values (before and after the comma).
Definition: util.c:107
RTC_dateTime_t::newCharDay
uint8_t newCharDay
Definition: rtc.h:73
cData_t::newMaxVolt
uint8_t newMaxVolt
Definition: conversion.h:101
RTC_dateTime_t::newCharYear
uint8_t newCharYear
Definition: rtc.h:85
Settings_t::vbatRight
char vbatRight[3]
Definition: conversion.h:142
Settings_t::measPeriodIndex
uint8_t measPeriodIndex
Definition: conversion.h:153
cData_t::newAh
uint8_t newAh
Definition: conversion.h:122
RTC_dateTime_t::min0
uint8_t min0
Definition: rtc.h:60
RTC_dateTime_t::month0
uint8_t month0
Definition: rtc.h:77
cData_t::aLeft
char aLeft[2]
Definition: conversion.h:106
Data_t::voltage
float voltage
Definition: conversion.h:54
Data_t::newVolt
uint8_t newVolt
Definition: conversion.h:57
Data_t::oldPower
float oldPower
Definition: conversion.h:74
RTC_dateTime_t::newCharHour
uint8_t newCharHour
Definition: rtc.h:58
RTC_dateTime_t::year1
uint16_t year1
Definition: rtc.h:83
Settings_t::periodChanged
uint8_t periodChanged
Definition: conversion.h:157
cData_t::vRight
char vRight[4]
Definition: conversion.h:97
Data_t::power
float power
Definition: conversion.h:73
cData_t::aMinRight
char aMinRight[5]
Definition: conversion.h:113
Settings_t::dateTimeChanged
uint8_t dateTimeChanged
Definition: conversion.h:159
RTC_dateTime_t::charMin
char charMin[3]
Definition: rtc.h:62
Data_t::newMinCurr
uint8_t newMinCurr
Definition: conversion.h:69
Settings_t::measPeriodS
uint16_t measPeriodS
Definition: conversion.h:155
cData_t::charRunSecs
char charRunSecs[3]
Definition: conversion.h:131
Settings_t::vbatCounter
uint8_t vbatCounter
Definition: conversion.h:144
cData_t::newMinCurr
uint8_t newMinCurr
Definition: conversion.h:114
RTC_dateTime_t::charYear
char charYear[5]
Definition: rtc.h:84
Data_t::newCurr
uint8_t newCurr
Definition: conversion.h:67
RTC_dateTime_t::sec1
uint8_t sec1
Definition: rtc.h:66
cData_t::ahRight
char ahRight[4]
Definition: conversion.h:121
Settings_t::newCharVbat
uint8_t newCharVbat
Definition: conversion.h:143
Data_t::firstVolt
uint8_t firstVolt
Definition: conversion.h:56
Settings_t::newSelDisplay
uint8_t newSelDisplay
Definition: conversion.h:149
RTC_dateTime_t::newCharSec
uint8_t newCharSec
Definition: rtc.h:68
cData_t::newMinVolt
uint8_t newMinVolt
Definition: conversion.h:104
RTC_dateTime_t::day0
uint8_t day0
Definition: rtc.h:70
Settings_t::changeDateTime
uint8_t changeDateTime
Definition: conversion.h:158
Data_t::minVoltage
float minVoltage
Definition: conversion.h:58
Data_t::newMaxCurr
uint8_t newMaxCurr
Definition: conversion.h:71
cData_t::vMaxRight
char vMaxRight[4]
Definition: conversion.h:100
Data_t::ah
float ah
Definition: conversion.h:76
cData_t::aMinLeft
char aMinLeft[2]
Definition: conversion.h:112
Settings_t::msWaitingStart
uint32_t msWaitingStart
Definition: conversion.h:169
RTC_dateTime_t::sec0
uint8_t sec0
Definition: rtc.h:65
Data_t::voltReceived
uint8_t voltReceived
Definition: conversion.h:53
Data_t::newWh
uint8_t newWh
Definition: conversion.h:79
RTC_dateTime_t::latest
uint8_t latest
Definition: rtc.h:53
cData_t::vMaxLeft
char vMaxLeft[3]
Definition: conversion.h:99
Data_t::firstCurr
uint8_t firstCurr
Definition: conversion.h:66
Data_t::minCurrent
float minCurrent
Definition: conversion.h:68
cData_t::newVolt
uint8_t newVolt
Definition: conversion.h:98
cData_t::vMinRight
char vMinRight[4]
Definition: conversion.h:103
Settings_t::remMeasPeriodS
uint16_t remMeasPeriodS
Definition: conversion.h:154
Settings_t::oldTIM3
uint16_t oldTIM3
Definition: conversion.h:163
cData_t::newRunMins
uint8_t newRunMins
Definition: conversion.h:130
RTC_dateTime_t::day1
uint8_t day1
Definition: rtc.h:71
cData_t::newRunSecs
uint8_t newRunSecs
Definition: conversion.h:132
Settings_t::vbatLeft
char vbatLeft[2]
Definition: conversion.h:141
Data_t::oldCurr
float oldCurr
Definition: conversion.h:65
cData_t::newWh
uint8_t newWh
Definition: conversion.h:125
Settings_t::secPassed
volatile uint8_t secPassed
Definition: conversion.h:164
Data_t::runMins
uint8_t runMins
Definition: conversion.h:83
Settings_t::newSec
uint8_t newSec
Definition: conversion.h:165
Settings_t::vbat
volatile float vbat
Definition: conversion.h:139
Settings_t::forceConv
uint8_t forceConv
Definition: conversion.h:162
cData_t::vMinLeft
char vMinLeft[3]
Definition: conversion.h:102
Settings_t::mode
uint8_t mode
Definition: conversion.h:146
uint32_to_charDec
void uint32_to_charDec(char *buf, uint32_t value, uint8_t totalChars)
Convert a uint32_t value to a decimal char array (string).
Definition: util.c:149
Settings_t::newVbat
volatile uint8_t newVbat
Definition: conversion.h:140
Data_t::newPow
uint8_t newPow
Definition: conversion.h:75
RTC_dateTime_t::hour1
uint8_t hour1
Definition: rtc.h:56
RTC_dateTime_t::month1
uint8_t month1
Definition: rtc.h:78
RTC_dateTime_t::firstUpdate
uint8_t firstUpdate
Definition: rtc.h:52
convertValues
void convertValues(void)
Function to convert the measurements to char-arrays.
Definition: conversion.c:172
Data_t::newRunMins
uint8_t newRunMins
Definition: conversion.h:84