You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							196 lines
						
					
					
						
							4.5 KiB
						
					
					
				
			
		
		
	
	
							196 lines
						
					
					
						
							4.5 KiB
						
					
					
				| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdbool.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| #include <assert.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #include <sys/mman.h>
 | |
| #include <sys/socket.h>
 | |
| #include <sys/un.h>
 | |
| 
 | |
| #include "ipc.h"
 | |
| 
 | |
| #include "visionipc.h"
 | |
| 
 | |
| typedef struct VisionPacketWire {
 | |
|   int type;
 | |
|   VisionPacketData d;
 | |
| } VisionPacketWire;
 | |
| 
 | |
| int vipc_connect() {
 | |
|   return ipc_connect(VIPC_SOCKET_PATH);
 | |
| }
 | |
| 
 | |
| 
 | |
| int vipc_recv(int fd, VisionPacket *out_p) {
 | |
|   VisionPacketWire p = {0};
 | |
|   VisionPacket p2 = {0};
 | |
|   int ret = ipc_sendrecv_with_fds(false, fd, &p, sizeof(p), (int*)p2.fds, VIPC_MAX_FDS, &p2.num_fds);
 | |
|   if (ret < 0) {
 | |
|     printf("vipc_recv err: %s\n", strerror(errno));
 | |
|   } else {
 | |
|     p2.type = p.type;
 | |
|     p2.d = p.d;
 | |
|     *out_p = p2;
 | |
|   }
 | |
|   //printf("%d = vipc_recv(%d, %d): %d %d %d %zu\n", ret, fd, p2.num_fds, out_p->d.stream_bufs.type, out_p->d.stream_bufs.width, out_p->d.stream_bufs.height, out_p->d.stream_bufs.buf_len);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int vipc_send(int fd, const VisionPacket *p2) {
 | |
|   assert(p2->num_fds <= VIPC_MAX_FDS);
 | |
| 
 | |
|   VisionPacketWire p = {
 | |
|     .type = p2->type,
 | |
|     .d = p2->d,
 | |
|   };
 | |
|   int ret = ipc_sendrecv_with_fds(true, fd, (void*)&p, sizeof(p), (int*)p2->fds, p2->num_fds, NULL);
 | |
|   //printf("%d = vipc_send(%d, %d): %d %d %d %zu\n", ret, fd, p2->num_fds, p2->d.stream_bufs.type, p2->d.stream_bufs.width, p2->d.stream_bufs.height, p2->d.stream_bufs.buf_len);
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| void vipc_bufs_load(VIPCBuf *bufs, const VisionStreamBufs *stream_bufs,
 | |
|                      int num_fds, const int* fds) {
 | |
|   for (int i=0; i<num_fds; i++) {
 | |
|     if (bufs[i].addr) {
 | |
|       munmap(bufs[i].addr, bufs[i].len);
 | |
|       bufs[i].addr = NULL;
 | |
|       close(bufs[i].fd);
 | |
|     }
 | |
|     bufs[i].fd = fds[i];
 | |
|     bufs[i].len = stream_bufs->buf_len;
 | |
|     bufs[i].addr = mmap(NULL, bufs[i].len,
 | |
|                         PROT_READ | PROT_WRITE,
 | |
|                         MAP_SHARED, bufs[i].fd, 0);
 | |
|     // printf("b %d %zu -> %p\n", bufs[i].fd, bufs[i].len, bufs[i].addr);
 | |
|     assert(bufs[i].addr != MAP_FAILED);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| int visionstream_init(VisionStream *s, VisionStreamType type, bool tbuffer, VisionStreamBufs *out_bufs_info) {
 | |
|   int err;
 | |
| 
 | |
|   memset(s, 0, sizeof(*s));
 | |
| 
 | |
|   s->last_idx = -1;
 | |
| 
 | |
|   s->ipc_fd = vipc_connect();
 | |
|   if (s->ipc_fd < 0) return -1;
 | |
| 
 | |
|   VisionPacket p = {
 | |
|     .type = VIPC_STREAM_SUBSCRIBE,
 | |
|     .d = { .stream_sub = {
 | |
|       .type = type,
 | |
|       .tbuffer = tbuffer,
 | |
|     }, },
 | |
|   };
 | |
|   err = vipc_send(s->ipc_fd, &p);
 | |
|   if (err < 0) {
 | |
|     close(s->ipc_fd);
 | |
|     s->ipc_fd = -1;
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   VisionPacket rp;
 | |
|   err = vipc_recv(s->ipc_fd, &rp);
 | |
|   if (err <= 0) {
 | |
|     close(s->ipc_fd);
 | |
|     s->ipc_fd = -1;
 | |
|     return -1;
 | |
|   }
 | |
|   assert(rp.type == VIPC_STREAM_BUFS);
 | |
|   assert(rp.d.stream_bufs.type == type);
 | |
| 
 | |
|   s->bufs_info = rp.d.stream_bufs;
 | |
| 
 | |
|   s->num_bufs = rp.num_fds;
 | |
|   s->bufs = calloc(s->num_bufs, sizeof(VIPCBuf));
 | |
|   assert(s->bufs);
 | |
| 
 | |
|   vipc_bufs_load(s->bufs, &rp.d.stream_bufs, s->num_bufs, rp.fds);
 | |
| 
 | |
|   if (out_bufs_info) {
 | |
|     *out_bufs_info = s->bufs_info;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| void visionstream_release(VisionStream *s) {
 | |
|   int err;
 | |
|   if (s->last_idx >= 0) {
 | |
|     VisionPacket rep = {
 | |
|       .type = VIPC_STREAM_RELEASE,
 | |
|       .d = { .stream_rel = {
 | |
|         .type = s->last_type,
 | |
|         .idx = s->last_idx,
 | |
|       }}
 | |
|     };
 | |
|     err = vipc_send(s->ipc_fd, &rep);
 | |
|     s->last_idx = -1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| VIPCBuf* visionstream_get(VisionStream *s, VIPCBufExtra *out_extra) {
 | |
|   int err;
 | |
| 
 | |
|   VisionPacket rp;
 | |
|   err = vipc_recv(s->ipc_fd, &rp);
 | |
|   if (err <= 0) {
 | |
|     return NULL;
 | |
|   }
 | |
|   assert(rp.type == VIPC_STREAM_ACQUIRE);
 | |
| 
 | |
|   if (s->last_idx >= 0) {
 | |
|     VisionPacket rep = {
 | |
|       .type = VIPC_STREAM_RELEASE,
 | |
|       .d = { .stream_rel = {
 | |
|         .type = s->last_type,
 | |
|         .idx = s->last_idx,
 | |
|       }}
 | |
|     };
 | |
|     err = vipc_send(s->ipc_fd, &rep);
 | |
|     if (err <= 0) {
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   s->last_type = rp.d.stream_acq.type;
 | |
|   s->last_idx = rp.d.stream_acq.idx;
 | |
|   assert(s->last_idx < s->num_bufs);
 | |
| 
 | |
|   if (out_extra) {
 | |
|     *out_extra = rp.d.stream_acq.extra;
 | |
|   }
 | |
| 
 | |
|   return &s->bufs[s->last_idx];
 | |
| }
 | |
| 
 | |
| void visionstream_destroy(VisionStream *s) {
 | |
|   int err;
 | |
| 
 | |
|   if (s->last_idx >= 0) {
 | |
|     VisionPacket rep = {
 | |
|       .type = VIPC_STREAM_RELEASE,
 | |
|       .d = { .stream_rel = {
 | |
|         .type = s->last_type,
 | |
|         .idx = s->last_idx,
 | |
|       }}
 | |
|     };
 | |
|     err = vipc_send(s->ipc_fd, &rep);
 | |
|     s->last_idx = -1;
 | |
|   }
 | |
| 
 | |
|   for (int i=0; i<s->num_bufs; i++) {
 | |
|     if (s->bufs[i].addr) {
 | |
|       munmap(s->bufs[i].addr, s->bufs[i].len);
 | |
|       s->bufs[i].addr = NULL;
 | |
|       close(s->bufs[i].fd);
 | |
|     }
 | |
|   }
 | |
|   if (s->bufs) free(s->bufs);
 | |
|   if (s->ipc_fd >= 0) close(s->ipc_fd);
 | |
| }
 | |
| 
 |