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