Skip to content

Commit 3108bb4

Browse files
committed
lin16: factorize code for exp5
Centralize the lin16 code. It should be used to better apply the specifications based on PMBus-Specification-Rev-1-3-1-Part-II-20150313.pdf from https://pmbus.org/specification-archives/
1 parent 2996bf7 commit 3108bb4

File tree

6 files changed

+44
-45
lines changed

6 files changed

+44
-45
lines changed

src/TODO

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
* use getopt_long() for each subcommand
22
* add a usage_long() for some complex commands
33
* improve main() using a table of token -> function
4-
* factorize the ldexp() from double to uint16_t, XXX libm is not needed when:
5-
double scaled = (exp5 < 0)
6-
? v * (double)(1u << (-exp5)) /* exp negative -> multiply */
7-
: v / (double)(1u << exp5); /* exp zero/positive -> divide */
4+
* compile using 'warning_level=everything',

src/pgood_cmd.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* SPDX-License-Identifier: AGPL-3.0-or-later */
22
#include "pmbus_io.h"
33
#include "util_json.h"
4+
#include "util_lin.h"
45

56
#include <jansson.h>
67
#include <string.h>
78
#include <stdio.h>
89
#include <stdlib.h>
910
#include <errno.h>
10-
#include <math.h>
1111

1212
static void
1313
usage_pgood(void) {
@@ -104,13 +104,7 @@ cmd_pgood(int fd, int argc, char *const *argv, int pretty) {
104104
return 2;
105105
}
106106
double v = strtod(on_v, NULL);
107-
/* N = v * 2^(−exp5) */
108-
double scaled = ldexp(v, -exp5);
109-
if (scaled < 0.0)
110-
scaled = 0.0;
111-
if (scaled > 65535.0)
112-
scaled = 65535.0;
113-
won = (uint16_t) (scaled + 0.5);
107+
won = units_to_lin16u(v, exp5);
114108

115109
set_on = 1;
116110
}
@@ -122,13 +116,7 @@ cmd_pgood(int fd, int argc, char *const *argv, int pretty) {
122116
return 2;
123117
}
124118
double v = strtod(off_v, NULL);
125-
/* N = v * 2^(−exp5) */
126-
double scaled = ldexp(v, -exp5);
127-
if (scaled < 0.0)
128-
scaled = 0.0;
129-
if (scaled > 65535.0)
130-
scaled = 65535.0;
131-
wof = (uint16_t) (scaled + 0.5);
119+
wof = units_to_lin16u(v, exp5);
132120

133121
set_off = 1;
134122
}

src/pmbus_io.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: AGPL-3.0-or-later */
22

33
#include "pmbus_io.h"
4+
#include "util_lin.h"
45

56
#include <linux/i2c-dev.h>
67
#include <i2c/smbus.h>
@@ -71,6 +72,7 @@ pmbus_send_byte(int fd, uint8_t cmd) {
7172
return i2c_smbus_write_byte(fd, cmd);
7273
}
7374

75+
/* see PMBus-Specification-Rev-1-3-1-Part-II-20150313.pdf, section 8.3 */
7476
int
7577
pmbus_get_vout_mode_exp(int fd, int *exp_out) {
7678
int v = pmbus_rd_byte(fd, PMBUS_VOUT_MODE);
@@ -105,8 +107,7 @@ pmbus_lin11_to_double(uint16_t raw) {
105107

106108
double
107109
pmbus_lin16u_to_double(uint16_t raw, int exp5) {
108-
/* value = raw * 2^exp5 */
109-
return ldexp((double)raw, exp5);
110+
return lin16u_to_units(raw, exp5);
110111
}
111112

112113
uint16_t

src/util_lin.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* SPDX-License-Identifier: AGPL-3.0-or-later */
2+
3+
#pragma once
4+
5+
#include <stdint.h>
6+
#include <math.h> /* ldexp: no need of libm */
7+
8+
/* TODO: align with PMBus-Specification-Rev-1-3-1-Part-II-20150313.pdf */
9+
10+
/* Round-to-nearest and saturate into [0, 65535] for non-negative doubles. */
11+
static inline uint16_t
12+
u16_round_sat_pos(double x) {
13+
if (isnan(x))
14+
return 0;
15+
16+
if (x >= 65535.0)
17+
return 65535;
18+
19+
return (uint16_t)(x + 0.5);
20+
}
21+
22+
/* Linear16-Unsigned: units = y * 2^N */
23+
static inline double
24+
lin16u_to_units(uint16_t y, int expN) {
25+
return ldexp((double)y, expN);
26+
}
27+
28+
/* lin16u = round(units * 2^{-N}) */
29+
static inline uint16_t units_to_lin16u(double units, int expN) {
30+
return u16_round_sat_pos(ldexp(units, -expN));
31+
}

src/vin_cmd.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* SPDX-License-Identifier: AGPL-3.0-or-later */
22
#include "pmbus_io.h"
33
#include "util_json.h"
4+
#include "util_lin.h"
45

56
#include <jansson.h>
67
#include <string.h>
78
#include <stdio.h>
89
#include <stdlib.h>
910
#include <errno.h>
10-
#include <math.h>
1111

1212
/* Uses LIN16U coding with user-provided exponent (exp5), or raw words. */
1313
static void
@@ -107,13 +107,7 @@ cmd_vin(int fd, int argc, char *const *argv, int pretty) {
107107
return 2;
108108
}
109109
double v = strtod(on_v, NULL);
110-
/* N = v * 2^(−exp5) */
111-
double scaled = ldexp(v, -exp5);
112-
if (scaled < 0.0)
113-
scaled = 0.0;
114-
if (scaled > 65535.0)
115-
scaled = 65535.0;
116-
won = (uint16_t) (scaled + 0.5);
110+
won = units_to_lin16u(v, exp5);
117111

118112
set_on = 1;
119113
}
@@ -125,13 +119,7 @@ cmd_vin(int fd, int argc, char *const *argv, int pretty) {
125119
return 2;
126120
}
127121
double v = strtod(off_v, NULL);
128-
/* N = v * 2^(−exp5) */
129-
double scaled = ldexp(v, -exp5);
130-
if (scaled < 0.0)
131-
scaled = 0.0;
132-
if (scaled > 65535.0)
133-
scaled = 65535.0;
134-
wof = (uint16_t) (scaled + 0.5);
122+
wof = units_to_lin16u(v, exp5);
135123

136124
set_off = 1;
137125
}

src/vout_cmd.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "pmbus_io.h"
44
#include "util_json.h"
5+
#include "util_lin.h"
56
#include <jansson.h>
67
#include <string.h>
78
#include <stdlib.h>
@@ -21,20 +22,13 @@
2122
static inline double
2223
lin16u_to_volts(uint16_t y, int exp5) {
2324
/* V = Y * 2^N */
24-
return (double) y *ldexp(1.0, exp5);
25+
return lin16u_to_units(y, exp5);
2526
}
2627

2728
static inline uint16_t
2829
volts_to_lin16u(double v, int exp5) {
2930
/* Y = round(V * 2^{-N}) */
30-
double scaled = v * ldexp(1.0, -exp5);
31-
if (scaled < 0.0)
32-
scaled = 0.0;
33-
if (scaled > 65535.0)
34-
scaled = 65535.0;
35-
36-
/* scaled is clamped to [0, 65535] already: llround(scaled), avoid libm */
37-
return (uint16_t)(scaled + 0.5);
31+
return units_to_lin16u(v, exp5);
3832
}
3933

4034
static int

0 commit comments

Comments
 (0)