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 <fcntl.h>
9 #include <inttypes.h>
10 #include <netdb.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <stdarg.h>
19 #include <stddef.h>
20 
21 #include "renode_api.h"
22 
23 struct renode {
24     int socket_fd;
25 };
26 
27 struct renode_machine {
28     renode_t *renode;
29     int32_t md;
30 };
31 
32 struct renode_adc {
33     renode_machine_t *machine;
34     int32_t id;
35 };
36 
37 struct renode_gpio {
38     renode_machine_t *machine;
39     int32_t id;
40 };
41 
42 #define SERVER_START_COMMAND "emulation CreateExternalControlServer \"<NAME>\""
43 #define SOCKET_INVALID -1
44 
45 #define unlikely(x) __builtin_expect(!!(x), 0)
46 #define assert(x) do { if (unlikely(!(x))) { fprintf(stderr, "Assert not met in %s:%d: %s\n", __FILE__, __LINE__, #x); return create_fatal_error_static(NULL); } } while (0)
47 #define assert_fmsg(x, ...) do { if (unlikely(!(x))) { fprintf(stderr, "Assert not met in %s:%d: %s\n", __FILE__, __LINE__, #x); return create_fatal_error(__VA_ARGS__); } } while (0)
48 #define assert_msg(x, msg) do { if (unlikely(!(x))) { fprintf(stderr, "Assert not met in %s:%d: %s\n", __FILE__, __LINE__, #x); return create_fatal_error_static(msg); } } while (0)
49 
50 // This is supposed to exit cause it's a fatal issue within the library code.
51 #define assert_exit(x) do { if (unlikely(!(x))) { fprintf(stderr, "Assert not met in %s:%d: %s\n", __FILE__, __LINE__, #x); exit(EXIT_FAILURE); } } while (0)
52 
53 #define return_error_if_fails(function) do { renode_error_t *_RE_ERROR; if ((_RE_ERROR = (function)) != NO_ERROR) return _RE_ERROR; } while (0)
54 
55 /* Each response frame starts with 1 byte of return code and the following command and data depend on the code value.
56  * Command is a 1 byte value of api_command_t.
57  * Data is a 4 byte little endian unsigned value for the `count`, followed by the `count` bytes of raw data.
58  * The comments next to enum values denote which parts of the frame should be expected.
59  */
60 
61 // matches ReturnCode enum in src/Renode/Network/ExternalControl/ExternalControlServer.cs
62 typedef enum {
63     COMMAND_FAILED, // code, command, data
64     FATAL_ERROR, // code, data
65     INVALID_COMMAND, // code, command
66     SUCCESS_WITH_DATA, // code, command, data
67     SUCCESS_WITHOUT_DATA, // code, command
68     SUCCESS_HANDSHAKE, // code
69     ASYNC_EVENT, // code, command, callback id, data
70 } return_code_t;
71 
72 // internal renode_error_t flags
73 #define ERROR_FREE_MESSAGE 0x01 // the message field needs to be freed
74 
75 #define ERROR_DYNAMIC_MESSAGE_SIZE 0x400
76 
xmalloc(size_t size)77 static void *xmalloc(size_t size)
78 {
79     void *result = malloc(size);
80     assert_exit(result != NULL);
81     return result;
82 }
83 
xcleanup(void * ptr)84 static void xcleanup(void *ptr)
85 {
86     free(*(void**)ptr);
87 }
88 
create_error_static(renode_error_code code,char * message)89 static renode_error_t *create_error_static(renode_error_code code, char *message)
90 {
91     renode_error_t *error = xmalloc(sizeof(renode_error_t));
92     error->code = code;
93     error->flags = 0;
94     error->message = message;
95     error->data = NULL;
96     return error;
97 }
98 
create_error_dynamic(renode_error_code code,char * message)99 static renode_error_t *create_error_dynamic(renode_error_code code, char *message)
100 {
101     renode_error_t *error = create_error_static(code, message);
102     error->flags |= ERROR_FREE_MESSAGE;
103     return error;
104 }
105 
106 #define create_connection_failed_error(message) create_error_static(ERR_COMMAND_FAILED, (message))
107 #define create_fatal_error_static(message) create_error_static(ERR_FATAL, (message))
108 
create_error(renode_error_code code,char * fmt,...)109 static renode_error_t *create_error(renode_error_code code, char *fmt, ...)
110 {
111     char *message = xmalloc(ERROR_DYNAMIC_MESSAGE_SIZE);
112     va_list ap;
113     va_start(ap, fmt);
114     vsnprintf(message, ERROR_DYNAMIC_MESSAGE_SIZE, fmt, ap);
115     va_end(ap);
116 
117     renode_error_t *error = create_error_static(code, message);
118     error->flags |= ERROR_FREE_MESSAGE;
119     return error;
120 }
121 
122 #define create_fatal_error(...) create_error(ERR_FATAL, __VA_ARGS__)
123 #define create_command_failed_error(...) create_error(ERR_COMMAND_FAILED, __VA_ARGS__)
124 
renode_free_error(renode_error_t * error)125 void renode_free_error(renode_error_t *error)
126 {
127     if (error->flags & ERROR_FREE_MESSAGE) {
128         free(error->message);
129     }
130     free(error);
131 }
132 
133 #define ERRMSG_FAILED_TO_READ_FROM_SOCKET "Failed to read from socket"
134 #define ERRMSG_FAILED_TO_WRITE_TO_SOCKET "Failed to write to socket"
135 #define ERRMSG_SOCKET_CLOSED "Socket was closed"
136 #define ERRMSG_UNEXPECTED_RETURN_CODE "Unexpected return code"
137 #define ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE "Received unexpected number of bytes"
138 #define ERRMSG_COMMAND_MISMATCH "received mismatched command"
139 
140 typedef enum {
141     ANY_COMMAND = 0,
142     RUN_FOR = 1,
143     GET_TIME,
144     GET_MACHINE,
145     ADC,
146     GPIO,
147     EVENT = -1,
148 } api_command_t;
149 
150 static uint8_t command_versions[][2] = {
151     { 0x0, 0x0 }, // reserved for size
152     { RUN_FOR, 0x0 },
153     { GET_TIME, 0x0 },
154     { GET_MACHINE, 0x0 },
155     { ADC, 0x0 },
156     { GPIO, 0x1 },
157 };
158 
write_or_fail(int socket_fd,const uint8_t * data,ssize_t count)159 static renode_error_t *write_or_fail(int socket_fd, const uint8_t *data, ssize_t count)
160 {
161     ssize_t sent;
162 
163     assert_msg(count > 0, "Usage error: attempted to write invalid number of bytes to socket");
164 
165     while (count > 0 && (sent = write(socket_fd, data, count)) > 0) {
166         count -= sent;
167     }
168 
169     if (sent <= 0) {
170         return create_connection_failed_error(ERRMSG_FAILED_TO_WRITE_TO_SOCKET);
171     }
172 
173     return NO_ERROR;
174 }
175 
read_byte_or_fail(int socket_fd,uint8_t * value)176 static renode_error_t *read_byte_or_fail(int socket_fd, uint8_t *value)
177 {
178     ssize_t received;
179 
180     if ((received = read(socket_fd, value, 1)) == 1) {
181         return NO_ERROR;
182     }
183 
184     if (received == 0) {
185         return create_connection_failed_error(ERRMSG_SOCKET_CLOSED);
186     }
187 
188     return create_connection_failed_error(ERRMSG_FAILED_TO_READ_FROM_SOCKET);
189 }
190 
191 
read_or_fail(int socket_fd,uint8_t * buffer,uint32_t count)192 static renode_error_t *read_or_fail(int socket_fd, uint8_t *buffer, uint32_t count)
193 {
194     ssize_t received;
195 
196     assert_msg(count > 0, "Usage error: attempted to read invalid number of bytes from socket");
197 
198     while (count > 0 && (received = read(socket_fd, buffer, count)) > 0) {
199         buffer += received;
200         count -= received;
201     }
202 
203     if (received == 0) {
204         return create_connection_failed_error(ERRMSG_SOCKET_CLOSED);
205     }
206 
207     if (received == -1) {
208         return create_connection_failed_error(ERRMSG_FAILED_TO_READ_FROM_SOCKET);
209     }
210 
211     return NO_ERROR;
212 }
213 
perform_handshake(int socket_fd)214 static renode_error_t *perform_handshake(int socket_fd)
215 {
216     *(uint16_t *)command_versions = sizeof(command_versions) / 2 - 1;
217 
218     return_error_if_fails(write_or_fail(socket_fd, (uint8_t *)command_versions, sizeof(command_versions)));
219 
220     uint8_t response;
221 
222     return_error_if_fails(read_byte_or_fail(socket_fd, &response));
223 
224     assert_msg(response == SUCCESS_HANDSHAKE, "API command version mismatch");
225 
226     return NO_ERROR;
227 }
228 
obtain_socket(int * socket_fd,const char * address,const char * port)229 static renode_error_t *obtain_socket(int *socket_fd, const char *address, const char *port)
230 {
231     struct addrinfo  hints;
232     struct addrinfo  *results, *rp;
233 
234     memset(&hints, 0, sizeof(hints));
235     hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
236     hints.ai_socktype = SOCK_STREAM; /* TCP socket */
237     hints.ai_protocol = 0;           /* Any protocol */
238     hints.ai_flags = 0;
239 
240     int error = getaddrinfo(address, port, &hints, &results);
241     assert_fmsg(!error, "Unable to find the server: %s", gai_strerror(error));
242 
243     for (rp = results; rp != NULL; rp = rp->ai_next) {
244 
245         *socket_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
246 
247         if (*socket_fd == -1) {
248             continue;
249         }
250 
251         if (connect(*socket_fd, rp->ai_addr, rp->ai_addrlen) == -1) {
252             close(*socket_fd);
253             continue;
254         }
255 
256         freeaddrinfo(results);
257         return NO_ERROR;
258     }
259 
260     fprintf(stderr,
261         "Failed to connect to the server using port %s.\n"
262         "Make sure the server in Renode has been started with: `" SERVER_START_COMMAND " %s`\n",
263         port, port);
264     return create_fatal_error_static("Unable to connect to the server");
265 }
266 
renode_connect(const char * port,renode_t ** renode)267 renode_error_t *renode_connect(const char *port, renode_t **renode)
268 {
269     int socket_fd = -1;
270 
271     assert(port != NULL && renode != NULL);
272 
273     return_error_if_fails(obtain_socket(&socket_fd, "localhost", port));
274 
275     return_error_if_fails(perform_handshake(socket_fd));
276 
277     *renode = xmalloc(sizeof(renode_t));
278     (*renode)->socket_fd = socket_fd;
279 
280     return NO_ERROR;
281 };
282 
renode_disconnect(renode_t ** renode)283 renode_error_t *renode_disconnect(renode_t **renode)
284 {
285     assert(renode != NULL && *renode != NULL);
286 
287     close((*renode)->socket_fd);
288     free(*renode);
289     *renode = NULL;
290 
291     return NO_ERROR;
292 }
293 
renode_send_header(renode_t * renode,api_command_t api_command,uint32_t data_size)294 static renode_error_t *renode_send_header(renode_t *renode, api_command_t api_command, uint32_t data_size)
295 {
296     uint8_t header[7] = {
297         'R', 'E', api_command
298     };
299 
300     *(uint32_t*)(header + 3) = data_size;
301 
302     return write_or_fail(renode->socket_fd, header, sizeof(header));
303 }
304 
renode_send_command(renode_t * renode,api_command_t api_command,const uint8_t * data,uint32_t data_size)305 static renode_error_t *renode_send_command(renode_t *renode, api_command_t api_command, const uint8_t *data, uint32_t data_size)
306 {
307     // `api_command` should be 1B non-negative integer.
308     assert_exit(renode != NULL && api_command >= 0 && api_command < 0xFF);
309 
310     return_error_if_fails(renode_send_header(renode, api_command, data_size));
311 
312     return write_or_fail(renode->socket_fd, data, data_size);
313 }
314 
renode_receive_byte(renode_t * renode,uint8_t * value)315 static renode_error_t *renode_receive_byte(renode_t *renode, uint8_t *value)
316 {
317     return read_byte_or_fail(renode->socket_fd, value);
318 }
319 
renode_receive_bytes(renode_t * renode,uint8_t * buffer,uint32_t count)320 static renode_error_t *renode_receive_bytes(renode_t *renode, uint8_t *buffer, uint32_t count)
321 {
322     return read_or_fail(renode->socket_fd, buffer, count);
323 }
324 
325 struct renode_event {
326     uint32_t ed;
327     api_command_t command;
328     uint32_t size;
329     uint8_t data[];
330 };
331 
332 #define MAX_CALLBACK_COUNT 1024
333 
334 typedef void (*raw_callback_t)(void *, void *);
335 
336 static raw_callback_t callbacks[MAX_CALLBACK_COUNT];
337 static void *callback_user_data[MAX_CALLBACK_COUNT];
338 static uint32_t callbacks_count;
339 
register_callback(raw_callback_t callback,void * user_data,uint32_t * ed)340 static renode_error_t *register_callback(raw_callback_t callback, void *user_data, uint32_t *ed)
341 {
342     assert_msg(callbacks_count < MAX_CALLBACK_COUNT, "Cannot register any more callbacks");
343 
344     callbacks[callbacks_count] = callback;
345     callback_user_data[callbacks_count] = user_data;
346 
347     *ed = callbacks_count;
348     callbacks_count += 1;
349 
350     return NO_ERROR;
351 }
352 
invoke_callback(struct renode_event * response)353 static renode_error_t *invoke_callback(struct renode_event *response)
354 {
355     switch(response->command)
356     {
357     case GPIO:
358         assert_msg(response->ed < callbacks_count, "Tried to invoke callback for an invalid event descriptor");
359         assert_msg(response->size == sizeof(renode_gpio_event_data_t), ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
360         renode_gpio_event_data_t *data = (renode_gpio_event_data_t*)response->data;
361 
362         callbacks[response->ed](callback_user_data[response->ed], data);
363         return NO_ERROR;
364     default:
365         assert_msg(false, "Tried to invoke callback for an invalid command");
366     }
367 }
368 
renode_receive_event(renode_t * renode,void ** buffer)369 static renode_error_t *renode_receive_event(renode_t *renode, void **buffer)
370 {
371     uint8_t command = 0;
372     uint32_t ed = 0;
373     uint32_t size = 0;
374 
375     return_error_if_fails(renode_receive_bytes(renode, &command, 1));
376     return_error_if_fails(renode_receive_bytes(renode, (uint8_t*)&ed, 4));
377     return_error_if_fails(renode_receive_bytes(renode, (uint8_t*)&size, 4));
378 
379     struct renode_event *event = xmalloc(sizeof(struct renode_event) + size);
380     event->ed = ed;
381     event->size = size;
382     event->command = command;
383 
384     renode_error_t *error = renode_receive_bytes(renode, (uint8_t*)&event->data, event->size);
385 
386     if (error != NO_ERROR) {
387         free(event);
388         return error;
389     }
390 
391     *buffer = event;
392     return NO_ERROR;
393 }
394 
renode_receive_response(renode_t * renode,api_command_t * command,void ** data_buffer,uint32_t buffer_size,uint32_t * data_size)395 static renode_error_t *renode_receive_response(renode_t *renode, api_command_t *command, void **data_buffer, uint32_t buffer_size, uint32_t *data_size)
396 {
397     uint8_t *buffer = *data_buffer;
398     uint8_t return_code;
399     uint8_t received_command;
400     *data_size = -1;
401 
402     return_error_if_fails(renode_receive_byte(renode, &return_code));
403 
404     switch (return_code) {
405         case COMMAND_FAILED:
406         case INVALID_COMMAND:
407         case SUCCESS_WITH_DATA:
408         case SUCCESS_WITHOUT_DATA:
409         case FATAL_ERROR:
410             break;
411         case ASYNC_EVENT:
412             return_error_if_fails(renode_receive_event(renode, data_buffer));
413             if (*command == EVENT || *command == ANY_COMMAND) {
414                 *command = EVENT;
415                 return NO_ERROR;
416             }
417             free(*data_buffer);
418             return create_fatal_error_static("received unexpected event");
419         default:
420             return create_fatal_error_static(ERRMSG_UNEXPECTED_RETURN_CODE);
421     }
422 
423     switch (return_code) {
424         case COMMAND_FAILED:
425         case INVALID_COMMAND:
426         case SUCCESS_WITH_DATA:
427         case SUCCESS_WITHOUT_DATA:
428             return_error_if_fails(renode_receive_byte(renode, &received_command));
429         case FATAL_ERROR:
430             break;
431         default:
432             return create_fatal_error_static(ERRMSG_UNEXPECTED_RETURN_CODE);
433     }
434 
435     switch (return_code) {
436         case COMMAND_FAILED:
437         case FATAL_ERROR:
438             return_error_if_fails(renode_receive_bytes(renode, (uint8_t*)data_size, 4));
439 
440             if (buffer_size < *data_size + 1) {
441                 buffer = xmalloc(*data_size + 1);
442             }
443             buffer[*data_size] = '\0';
444 
445             return_error_if_fails(renode_receive_bytes(renode, buffer, *data_size));
446             break;
447         case SUCCESS_WITH_DATA:
448             return_error_if_fails(renode_receive_bytes(renode, (uint8_t*)data_size, 4));
449 
450             if (buffer_size < *data_size) {
451                 return create_fatal_error_static("Buffer too small");
452             }
453 
454             return_error_if_fails(renode_receive_bytes(renode, buffer, *data_size));
455             break;
456         case INVALID_COMMAND:
457         case SUCCESS_WITHOUT_DATA:
458             *data_size = 0;
459             break;
460         default:
461             return create_fatal_error_static(ERRMSG_UNEXPECTED_RETURN_CODE);
462     }
463 
464     renode_error_code error_code = ERR_NO_ERROR;
465     switch (return_code) {
466         case COMMAND_FAILED:
467             error_code = ERR_COMMAND_FAILED;
468             break;
469         case FATAL_ERROR:
470             error_code = ERR_COMMAND_FAILED;
471             break;
472         default:
473             break;
474     }
475 
476     if (error_code != ERR_NO_ERROR) {
477         return create_error_dynamic(error_code, (char *)buffer);
478     }
479 
480     if (return_code == INVALID_COMMAND) {
481         return create_fatal_error_static("received invalid command error");
482     }
483 
484     if (*command != ANY_COMMAND && received_command != *command) {
485         return create_fatal_error_static(ERRMSG_COMMAND_MISMATCH);
486     }
487     *command = received_command;
488 
489     return NO_ERROR;
490 }
491 
renode_execute_command(renode_t * renode,api_command_t api_command,void * data_buffer,uint32_t buffer_size,uint32_t sent_data_size,uint32_t * received_data_size)492 static renode_error_t *renode_execute_command(renode_t *renode, api_command_t api_command, void *data_buffer, uint32_t buffer_size, uint32_t sent_data_size, uint32_t *received_data_size)
493 {
494     assert(api_command != ANY_COMMAND && api_command != EVENT);
495     assert(buffer_size >= sent_data_size);
496 
497     return_error_if_fails(renode_send_command(renode, api_command, data_buffer, sent_data_size));
498 
499     uint32_t ignored_data_size;
500     void **buffer = &data_buffer;
501     return_error_if_fails(renode_receive_response(renode, &api_command, buffer, buffer_size, received_data_size == NULL ? &ignored_data_size : received_data_size));
502 
503     return NO_ERROR;
504 }
505 
renode_get_machine(renode_t * renode,const char * name,renode_machine_t ** machine)506 renode_error_t *renode_get_machine(renode_t *renode, const char *name, renode_machine_t **machine)
507 {
508     uint32_t name_length = strlen(name);
509     uint32_t data_size = name_length + sizeof(int32_t);
510     int32_t *data __attribute__ ((__cleanup__(xcleanup))) = xmalloc(data_size);
511 
512     data[0] = name_length;
513     memcpy(data + 1, name, name_length);
514 
515     return_error_if_fails(renode_execute_command(renode, GET_MACHINE, data, data_size, data_size, &data_size));
516 
517     assert_msg(data_size == 4, "received unexpected number of bytes");
518 
519     assert_msg(data[0] >= 0, "received invalid machine descriptor");
520 
521     *machine = xmalloc(sizeof(renode_machine_t));
522     (*machine)->renode = renode;
523     (*machine)->md = data[0];
524 
525     return NO_ERROR;
526 }
527 
renode_get_instance_descriptor(renode_machine_t * machine,api_command_t api_command,const char * name,int32_t * instance_descriptor)528 static renode_error_t *renode_get_instance_descriptor(renode_machine_t *machine, api_command_t api_command, const char *name, int32_t *instance_descriptor)
529 {
530     uint32_t name_length = strlen(name);
531     uint32_t data_size = name_length + sizeof(int32_t) * 3;
532     int32_t *data __attribute__ ((__cleanup__(xcleanup))) = xmalloc(data_size);
533 
534     data[0] = -1;
535     data[1] = machine->md;
536     data[2] = name_length;
537     memcpy(data + 3, name, name_length);
538 
539     return_error_if_fails(renode_execute_command(machine->renode, api_command, data, data_size, data_size, &data_size));
540 
541     assert_msg(data_size == 4, "received unexpected number of bytes");
542 
543     *instance_descriptor = data[0];
544 
545     assert_msg(*instance_descriptor >= 0, "received invalid instance descriptor");
546 
547     return NO_ERROR;
548 }
549 
550 struct __attribute__((packed)) run_for_out {
551     uint8_t header[2];
552     uint8_t api_command;
553     uint32_t data_size;
554     uint64_t microseconds;
555 };
556 
renode_run_for(renode_t * renode,renode_time_unit_t unit,uint64_t value)557 renode_error_t *renode_run_for(renode_t *renode, renode_time_unit_t unit, uint64_t value)
558 {
559     assert(renode != NULL && value < UINT64_MAX / unit);
560 
561     struct run_for_out data = {
562         .header = {'R', 'E'},
563         .api_command = RUN_FOR,
564         .data_size = sizeof(data.microseconds)
565     };
566     switch (unit) {
567         case TU_MICROSECONDS:
568         case TU_MILLISECONDS:
569         case TU_SECONDS:
570             // The enum values are equal to 1 `unit` expressed in microseconds.
571             data.microseconds = value * unit;
572             break;
573         default:
574             assert_fmsg(false, "Invalid unit: %d\n", unit);
575     }
576 
577     return_error_if_fails(write_or_fail(renode->socket_fd, (uint8_t*)&data, sizeof(data)));
578 
579     api_command_t command;
580     do {
581         command = ANY_COMMAND;
582 
583         uint32_t response_size;
584         void *buffer = &data;
585         return_error_if_fails(renode_receive_response(renode, &command, &buffer, sizeof(data), &response_size));
586 
587         if (command == RUN_FOR) {
588             break;
589         }
590 
591         if (command != EVENT) {
592             return create_fatal_error_static(ERRMSG_COMMAND_MISMATCH);
593         }
594 
595         struct renode_event *event = buffer;
596         renode_error_t *error = invoke_callback(event);
597         free(event);
598 
599         if (error != NO_ERROR) {
600             return error;
601         }
602     }
603     while(command != RUN_FOR);
604 
605     return NO_ERROR;
606 }
607 
renode_get_current_time(renode_t * renode,renode_time_unit_t unit,uint64_t * current_time)608 renode_error_t *renode_get_current_time(renode_t *renode, renode_time_unit_t unit, uint64_t *current_time)
609 {
610     assert(renode != NULL);
611 
612     uint64_t divider;
613     switch (unit) {
614         case TU_MICROSECONDS:
615         case TU_MILLISECONDS:
616         case TU_SECONDS:
617             // The enum values are equal to 1 `unit` expressed in microseconds.
618             divider = unit;
619             break;
620         default:
621             assert_fmsg(false, "Invalid unit: %d\n", unit);
622     }
623 
624     uint32_t response_size;
625     return_error_if_fails(renode_execute_command(renode, GET_TIME, current_time, sizeof(*current_time), sizeof(*current_time), &response_size));
626 
627     assert_msg(response_size == sizeof(*current_time), ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
628 
629     *current_time /= divider;
630 
631     return NO_ERROR;
632 }
633 
renode_get_adc(renode_machine_t * machine,const char * name,renode_adc_t ** adc)634 renode_error_t *renode_get_adc(renode_machine_t *machine, const char *name, renode_adc_t **adc)
635 {
636     int32_t id;
637     return_error_if_fails(renode_get_instance_descriptor(machine, ADC, name, &id));
638 
639     *adc = xmalloc(sizeof(renode_adc_t));
640     (*adc)->machine = machine;
641     (*adc)->id = id;
642 
643     return NO_ERROR;
644 }
645 
646 typedef enum {
647     GET_CHANNEL_COUNT = 0,
648     GET_CHANNEL_VALUE,
649     SET_CHANNEL_VALUE,
650 } adc_command_t;
651 
652 typedef union {
653     struct {
654         int32_t id;
655         int8_t command;
656         int32_t channel;
657         uint32_t value;
658     } __attribute__((packed)) out;
659 
660     struct {
661         int32_t count;
662     } get_count_result;
663 
664     struct {
665         uint32_t value;
666     } get_value_result;
667 } adc_frame_t;
668 
renode_get_adc_channel_count(renode_adc_t * adc,int32_t * count)669 renode_error_t *renode_get_adc_channel_count(renode_adc_t *adc, int32_t *count)
670 {
671     // adc id, adc command -> count
672     adc_frame_t frame = {
673         .out = {
674             .id = adc->id,
675             .command = GET_CHANNEL_COUNT,
676         },
677     };
678 
679     uint32_t response_size;
680     return_error_if_fails(renode_execute_command(adc->machine->renode, ADC, &frame, sizeof(frame), offsetof(adc_frame_t, out.channel), &response_size));
681 
682     assert_msg(response_size == sizeof(*count), ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
683 
684     *count = frame.get_count_result.count;
685 
686     return NO_ERROR;
687 }
688 
renode_get_adc_channel_value(renode_adc_t * adc,int32_t channel,uint32_t * value)689 renode_error_t *renode_get_adc_channel_value(renode_adc_t *adc, int32_t channel, uint32_t *value)
690 {
691     // adc id, adc command, channel index -> value
692     adc_frame_t frame = {
693         .out = {
694             .id = adc->id,
695             .command = GET_CHANNEL_VALUE,
696             .channel = channel,
697         },
698     };
699 
700     uint32_t response_size;
701     return_error_if_fails(renode_execute_command(adc->machine->renode, ADC, &frame, sizeof(frame), offsetof(adc_frame_t, out.value), &response_size));
702 
703     assert_msg(response_size == sizeof(*value), ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
704 
705     *value = frame.get_value_result.value;
706 
707     return NO_ERROR;
708 }
709 
renode_set_adc_channel_value(renode_adc_t * adc,int32_t channel,uint32_t value)710 renode_error_t *renode_set_adc_channel_value(renode_adc_t *adc, int32_t channel, uint32_t value)
711 {
712     // adc id, adc command, channel index, value -> ()
713     adc_frame_t frame = {
714         .out = {
715             .id = adc->id,
716             .command = SET_CHANNEL_VALUE,
717             .channel = channel,
718             .value = value,
719         },
720     };
721 
722     uint32_t response_size;
723     return_error_if_fails(renode_execute_command(adc->machine->renode, ADC, &frame, sizeof(frame), sizeof(frame.out), &response_size));
724 
725     assert_msg(response_size == 0, ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
726 
727     return NO_ERROR;
728 }
729 
renode_get_gpio(renode_machine_t * machine,const char * name,renode_gpio_t ** gpio)730 renode_error_t *renode_get_gpio(renode_machine_t *machine, const char *name, renode_gpio_t **gpio)
731 {
732     int32_t id;
733     return_error_if_fails(renode_get_instance_descriptor(machine, GPIO, name, &id));
734 
735     *gpio = xmalloc(sizeof(renode_gpio_t));
736     (*gpio)->machine = machine;
737     (*gpio)->id = id;
738 
739     return NO_ERROR;
740 }
741 
742 typedef enum {
743     GET_STATE,
744     SET_STATE,
745     REGISTER_EVENT,
746 } gpio_command_t;
747 
748 typedef union {
749     struct {
750         int32_t id;
751         int8_t command;
752         int32_t number;
753         uint8_t state;
754     } __attribute__((packed)) out;
755 
756     struct {
757         uint8_t value;
758     } get_state_result;
759 } gpio_frame_t;
760 
renode_get_gpio_state(renode_gpio_t * gpio,int32_t id,bool * state)761 renode_error_t *renode_get_gpio_state(renode_gpio_t *gpio, int32_t id, bool *state)
762 {
763     // gpio id, gpio command, pin number -> state
764     gpio_frame_t frame = {
765         .out = {
766             .id = gpio->id,
767             .command = GET_STATE,
768             .number = id,
769         },
770     };
771     uint8_t value = *state;
772 
773     uint32_t response_size;
774     return_error_if_fails(renode_execute_command(gpio->machine->renode, GPIO, &frame, sizeof(frame), offsetof(gpio_frame_t, out.state), &response_size));
775 
776     assert_msg(response_size == sizeof(value), ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
777 
778     *state = frame.get_state_result.value;
779 
780     return NO_ERROR;
781 }
782 
renode_set_gpio_state(renode_gpio_t * gpio,int32_t id,bool state)783 renode_error_t *renode_set_gpio_state(renode_gpio_t *gpio, int32_t id, bool state)
784 {
785     // gpio id, gpio command, pin number, state -> ()
786     gpio_frame_t frame = {
787         .out = {
788             .id = gpio->id,
789             .command = SET_STATE,
790             .number = id,
791             .state = state,
792         },
793     };
794 
795     uint32_t response_size;
796     return_error_if_fails(renode_execute_command(gpio->machine->renode, GPIO, &frame, sizeof(frame), sizeof(frame.out), &response_size));
797 
798     assert_msg(response_size == 0, ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
799 
800     return NO_ERROR;
801 }
802 
803 struct gpio_callback_data
804 {
805     bool current_state;
806 };
807 
808 struct __attribute__((packed)) event_gpio_frame
809 {
810     int32_t id;
811     int8_t command;
812     int32_t number;
813     int32_t ed;
814 };
815 
renode_register_gpio_state_change_callback(renode_gpio_t * gpio,int32_t id,void * user_data,void (* callback)(void *,renode_gpio_event_data_t *))816 renode_error_t *renode_register_gpio_state_change_callback(renode_gpio_t *gpio, int32_t id, void *user_data, void (*callback)(void *, renode_gpio_event_data_t *))
817 {
818     uint32_t ed;
819     return_error_if_fails(register_callback((raw_callback_t)callback, user_data, &ed));
820 
821     struct event_gpio_frame frame = {
822         .id = gpio->id,
823         .command = REGISTER_EVENT,
824         .number = id,
825         .ed = ed,
826     };
827 
828     uint32_t response_size;
829     return_error_if_fails(renode_execute_command(gpio->machine->renode, GPIO, &frame, sizeof(frame), sizeof(frame), &response_size));
830 
831     assert_msg(response_size == 0, ERRMSG_UNEXPECTED_RESPONSE_PAYLOAD_SIZE);
832 
833     return NO_ERROR;
834 }
835