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> <GPIO_NAME> <NUMBER> [true|false|event]",
20 argv0);
21 exit(EXIT_FAILURE);
22 }
23
get_error_message(renode_error_t * error)24 char *get_error_message(renode_error_t *error)
25 {
26 if (error->message == NULL)
27 {
28 return "<no message>";
29 }
30 return error->message;
31 }
32
try_renode_disconnect(renode_t ** renode)33 int try_renode_disconnect(renode_t **renode)
34 {
35 renode_error_t *error;
36 if ((error = renode_disconnect(renode)) != NO_ERROR) {
37 fprintf(stderr, "Disconnecting from Renode failed with: %s\n", get_error_message(error));
38 return -1;
39 }
40 return 0;
41 }
42
43 typedef struct {
44 char *machine_name;
45 char *gpio_name;
46 int pin_no;
47 bool run;
48 } gpio_event_user_data;
49
gpio_callback(void * user_data,renode_gpio_event_data_t * event_data)50 void gpio_callback(void *user_data, renode_gpio_event_data_t *event_data)
51 {
52 gpio_event_user_data *udata = (gpio_event_user_data *)user_data;
53 printf("%s: GPIO #%d in %s %sset", udata->machine_name, udata->pin_no, udata->gpio_name, event_data->state ? "" : "un");
54 printf(" at %lu us\n", event_data->timestamp_us);
55 udata->run = false;
56 }
57
main(int argc,char ** argv)58 int main(int argc, char **argv)
59 {
60 if (argc < 5 || 6 < argc) {
61 exit_with_usage_info(argv[0]);
62 }
63 char *machine_name = argv[2];
64 char *gpio_name = argv[3];
65 bool set = argc == 6;
66 bool state = false;
67 bool wait_for_event = false;
68
69 char *endptr;
70 // base=0 tries to figure out the number's base automatically.
71 int32_t number = strtol(argv[4], &endptr, /* base: */ 0);
72 if (errno != 0) {
73 perror("conversion to uint32_t value");
74 exit(EXIT_FAILURE);
75 }
76
77 if (endptr == argv[4] || *endptr != '\0') {
78 exit_with_usage_info(argv[0]);
79 }
80
81 if (set)
82 {
83 if (strcmp(argv[5], "true") != 0 && strcmp(argv[5], "false") != 0 && strcmp(argv[5], "event")) {
84 exit_with_usage_info(argv[0]);
85 }
86 state = argv[5][0] == 't';
87 wait_for_event = argv[5][0] == 'e';
88 }
89
90 // get Renode, machine and GPIO instances
91
92 renode_error_t *error;
93 renode_t *renode;
94 if ((error = renode_connect(argv[1], &renode)) != NO_ERROR) {
95 fprintf(stderr, "Connecting to Renode failed with: %s\n", get_error_message(error));
96 goto fail;
97 }
98
99 renode_machine_t *machine;
100 if ((error = renode_get_machine(renode, machine_name, &machine)) != NO_ERROR) {
101 fprintf(stderr, "Getting '%s' machine object failed with: %s\n", machine_name, get_error_message(error));
102 goto fail_renode;
103 }
104
105 renode_gpio_t *gpio;
106 if ((error = renode_get_gpio(machine, gpio_name, &gpio)) != NO_ERROR) {
107 fprintf(stderr, "Getting '%s' ADC object failed with: %s\n", gpio_name, get_error_message(error));
108 goto fail_machine;
109 }
110
111 // perform get/set
112
113 if (wait_for_event) {
114 gpio_event_user_data user_data = (gpio_event_user_data){
115 .machine_name = machine_name,
116 .gpio_name = gpio_name,
117 .pin_no = number,
118 .run = true
119 };
120
121 if ((error = renode_register_gpio_state_change_callback(gpio, number, &user_data, gpio_callback)) != NO_ERROR) {
122 fprintf(stderr, "Registering event on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
123 goto fail_gpio;
124 }
125
126 while (user_data.run) {
127 if ((error = renode_run_for(renode, TU_SECONDS, 60)) != NO_ERROR) {
128 fprintf(stderr, "Run for failed with: %s\n", get_error_message(error));
129 goto fail_gpio;
130 }
131 }
132 } else if (set) {
133 if ((error = renode_set_gpio_state(gpio, number, state)) != NO_ERROR) {
134 fprintf(stderr, "Setting state on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
135 goto fail_gpio;
136 }
137
138 printf("GPIO set to: %s\n", state ? "true" : "false");
139 } else {
140 if ((error = renode_get_gpio_state(gpio, number, &state)) != NO_ERROR) {
141 fprintf(stderr, "Getting state on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
142 goto fail_gpio;
143 }
144
145 printf("GPIO state: %s\n", state ? "true" : "false");
146 }
147
148 // clean up
149
150 free(gpio);
151 free(machine);
152 if (try_renode_disconnect(&renode)) {
153 exit(EXIT_FAILURE);
154 }
155
156 exit(EXIT_SUCCESS);
157
158 fail_gpio:
159 free(gpio);
160 fail_machine:
161 free(machine);
162 fail_renode:
163 try_renode_disconnect(&renode);
164 free(renode);
165 fail:
166 renode_free_error(error);
167 exit(EXIT_FAILURE);
168 }
169