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