1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under MIT License.
5 // Full license text is available in 'licenses/MIT.txt' file.
6 //
7 #include <errno.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "renode_api.h"
14
exit_with_usage_info(const char * argv0)15 void exit_with_usage_info(const char *argv0)
16 {
17 fprintf(stderr,
18 "Usage:\n"
19 " %s <PORT> <MACHINE_NAME> <ADC_NAME> <VALUE_WITH_UNIT>\n"
20 " where:\n"
21 " * <VALUE_WITH_UNIT> is an unsigned integer with a voltage unit, e.g.: '100mV'\n"
22 " * accepted voltage units are 'V', 'mV' and 'uV' (for microvolts)\n",
23 argv0);
24 exit(EXIT_FAILURE);
25 }
26
get_error_message(renode_error_t * error)27 char *get_error_message(renode_error_t *error)
28 {
29 if (error->message == NULL)
30 {
31 return "<no message>";
32 }
33 return error->message;
34 }
35
try_renode_disconnect(renode_t ** renode)36 int try_renode_disconnect(renode_t **renode)
37 {
38 renode_error_t *error;
39 if ((error = renode_disconnect(renode)) != NO_ERROR) {
40 fprintf(stderr, "Disconnecting from Renode failed with: %s\n", get_error_message(error));
41 return -1;
42 }
43 return 0;
44 }
45
voltage_string(uint32_t value)46 char *voltage_string(uint32_t value)
47 {
48 static char buffer[32];
49 uint32_t integer, fraction;
50
51 if ((integer = (value / 1000000))) {
52 fraction = value % 1000000;
53 snprintf(buffer, 32, "%u.%06uV", integer, fraction);
54 }
55 else if ((integer = (value / 1000))) {
56 fraction = value % 1000;
57 snprintf(buffer, 32, "%u.%03umV", integer, fraction);
58 }
59 else {
60 snprintf(buffer, 32, "%uuV", value);
61 }
62
63 return buffer;
64 }
65
main(int argc,char ** argv)66 int main(int argc, char **argv)
67 {
68 if (argc != 5) {
69 exit_with_usage_info(argv[0]);
70 }
71 char *machine_name = argv[2];
72 char *adc_name = argv[3];
73
74 char *endptr;
75 // base=0 tries to figure out the number's base automatically.
76 uint64_t value = strtoul(argv[4], &endptr, /* base: */ 0);
77 if (errno != 0) {
78 perror("conversion to uint32_t value");
79 exit(EXIT_FAILURE);
80 }
81
82 if (endptr == argv[4]) {
83 exit_with_usage_info(argv[0]);
84 }
85
86 switch (*endptr) {
87 case 'u':
88 // the unit used with the API
89 break;
90 case 'm':
91 value *= 1000;
92 break;
93 case 'V':
94 value *= 1000000;
95 break;
96 default:
97 exit_with_usage_info(argv[0]);
98 }
99
100 if (value > UINT32_MAX) {
101 fprintf(stderr, "Voltage value too big\n");
102 exit(EXIT_FAILURE);
103 }
104
105 // get Renode, machine and ADC instances
106
107 renode_error_t *error;
108 renode_t *renode;
109 if ((error = renode_connect(argv[1], &renode)) != NO_ERROR) {
110 fprintf(stderr, "Connecting to Renode failed with: %s\n", get_error_message(error));
111 goto fail;
112 }
113
114 renode_machine_t *machine;
115 if ((error = renode_get_machine(renode, machine_name, &machine)) != NO_ERROR) {
116 fprintf(stderr, "Getting '%s' machine object failed with: %s\n", machine_name, get_error_message(error));
117 goto fail_renode;
118 }
119
120 renode_adc_t *adc;
121 if ((error = renode_get_adc(machine, adc_name, &adc)) != NO_ERROR) {
122 fprintf(stderr, "Getting '%s' ADC object failed with: %s\n", adc_name, get_error_message(error));
123 goto fail_machine;
124 }
125
126 // assert that at least one channel exists
127
128 int32_t ch_count;
129 if ((error = renode_get_adc_channel_count(adc, &ch_count)) != NO_ERROR) {
130 fprintf(stderr, "Getting channel count for '%s' failed with: %s\n", adc_name, get_error_message(error));
131 goto fail_adc;
132 }
133
134 if (ch_count < 1) {
135 fprintf(stderr, "Expected at least one ADC channel\n");
136 goto fail_adc;
137 }
138 printf("[INFO] # of channels: %d\n", ch_count);
139
140 // get current value, set the new value and assert that new current value is set
141
142 uint32_t val0;
143 if ((error = renode_get_adc_channel_value(adc, 0, &val0)) != NO_ERROR) {
144 fprintf(stderr, "Getting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
145 goto fail_adc;
146 }
147
148 printf("ADC value: %s\n", voltage_string(val0));
149
150 uint32_t val1 = value;
151 if ((error = renode_set_adc_channel_value(adc, 0, val1)) != NO_ERROR) {
152 fprintf(stderr, "Setting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
153 goto fail_adc;
154 }
155
156 printf("ADC value set to %s\n", voltage_string(val1));
157
158 uint32_t val2;
159 if ((error = renode_get_adc_channel_value(adc, 0, &val2)) != NO_ERROR) {
160 fprintf(stderr, "Getting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
161 goto fail_adc;
162 }
163
164 printf("ADC value: %s\n", voltage_string(val2));
165
166 // clean up
167
168 free(adc);
169 free(machine);
170 if (try_renode_disconnect(&renode)) {
171 exit(EXIT_FAILURE);
172 }
173
174 if (val1 != val2) {
175 fprintf(stderr, "ADC value doesn't match set value\n");
176 exit(EXIT_FAILURE);
177 }
178
179 exit(EXIT_SUCCESS);
180
181 fail_adc:
182 free(adc);
183 fail_machine:
184 free(machine);
185 fail_renode:
186 try_renode_disconnect(&renode);
187 free(renode);
188 fail:
189 renode_free_error(error);
190 exit(EXIT_FAILURE);
191 }
192