build/sim: improve timebase calculation (strict checks) and update modules
[litex.git] / litex / build / sim / core / modules / serial2tcp / serial2tcp.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "error.h"
5 #include <unistd.h>
6 #include <event2/listener.h>
7 #include <event2/util.h>
8 #include <event2/event.h>
9
10 #include <json-c/json.h>
11 #include "modules.h"
12
13 struct session_s {
14 char *tx;
15 char *tx_valid;
16 char *tx_ready;
17 char *rx;
18 char *rx_valid;
19 char *rx_ready;
20 char *sys_clk;
21 struct event *ev;
22 char databuf[2048];
23 int data_start;
24 int datalen;
25 int fd;
26 };
27
28 struct event_base *base;
29
30 int litex_sim_module_get_args( char *args, char *arg, char **val)
31 {
32 int ret = RC_OK;
33 json_object *jsobj = NULL;
34 json_object *obj = NULL;
35 char *value = NULL;
36 int r;
37
38 jsobj = json_tokener_parse(args);
39 if(NULL==jsobj) {
40 fprintf(stderr, "Error parsing json arg: %s \n", args);
41 ret=RC_JSERROR;
42 goto out;
43 }
44 if(!json_object_is_type(jsobj, json_type_object)) {
45 fprintf(stderr, "Arg must be type object! : %s \n", args);
46 ret=RC_JSERROR;
47 goto out;
48 }
49 obj=NULL;
50 r = json_object_object_get_ex(jsobj, arg, &obj);
51 if(!r) {
52 fprintf(stderr, "Could not find object: \"%s\" (%s)\n", arg, args);
53 ret=RC_JSERROR;
54 goto out;
55 }
56 value=strdup(json_object_get_string(obj));
57
58 out:
59 *val = value;
60 return ret;
61 }
62
63 static int litex_sim_module_pads_get( struct pad_s *pads, char *name, void **signal)
64 {
65 int ret = RC_OK;
66 void *sig = NULL;
67 int i;
68
69 if(!pads || !name || !signal) {
70 ret = RC_INVARG;
71 goto out;
72 }
73
74 i = 0;
75 while(pads[i].name) {
76 if(!strcmp(pads[i].name, name)) {
77 sig = (void*)pads[i].signal;
78 break;
79 }
80 i++;
81 }
82
83 out:
84 *signal = sig;
85 return ret;
86 }
87
88 static int serial2tcp_start(void *b)
89 {
90 base = (struct event_base *)b;
91 printf("[serial2tcp] loaded (%p)\n", base);
92 return RC_OK;
93 }
94
95 void read_handler(int fd, short event, void *arg)
96 {
97 struct session_s *s = (struct session_s*)arg;
98 char buffer[1024];
99 ssize_t read_len;
100
101 int i;
102
103 read_len = read(fd, buffer, 1024);
104 for(i = 0; i < read_len; i++)
105 {
106 s->databuf[(s->data_start + s->datalen ) % 2048] = buffer[i];
107 s->datalen++;
108 }
109 }
110
111 static void event_handler(int fd, short event, void *arg)
112 {
113 if (event & EV_READ)
114 read_handler(fd, event, arg);
115 }
116
117 static void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx)
118 {
119 struct session_s *s = (struct session_s*)ctx;
120 struct timeval tv = {1, 0};
121
122 s->fd = fd;
123 s->ev = event_new(base, fd, EV_READ | EV_PERSIST , event_handler, s);
124 event_add(s->ev, &tv);
125 }
126
127 static void
128 accept_error_cb(struct evconnlistener *listener, void *ctx)
129 {
130 struct event_base *base = evconnlistener_get_base(listener);
131 eprintf("ERRROR\n");
132
133 event_base_loopexit(base, NULL);
134 }
135
136 static int serial2tcp_new(void **sess, char *args)
137 {
138 int ret = RC_OK;
139 struct session_s *s = NULL;
140 char *cport = NULL;
141 int port;
142 struct evconnlistener *listener;
143 struct sockaddr_in sin;
144
145 if(!sess) {
146 ret = RC_INVARG;
147 goto out;
148 }
149
150 ret = litex_sim_module_get_args(args, "port", &cport);
151 if(RC_OK != ret)
152 goto out;
153
154 printf("Found port %s\n", cport);
155 sscanf(cport, "%d", &port);
156 free(cport);
157 if(!port) {
158 ret = RC_ERROR;
159 fprintf(stderr, "Invalid port selected!\n");
160 goto out;
161 }
162
163 s=(struct session_s*)malloc(sizeof(struct session_s));
164 if(!s) {
165 ret = RC_NOENMEM;
166 goto out;
167 }
168 memset(s, 0, sizeof(struct session_s));
169
170 memset(&sin, 0, sizeof(sin));
171 sin.sin_family = AF_INET;
172 sin.sin_addr.s_addr = htonl(0);
173 sin.sin_port = htons(port);
174 listener = evconnlistener_new_bind(base, accept_conn_cb, s, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&sin, sizeof(sin));
175 if (!listener) {
176 ret=RC_ERROR;
177 eprintf("Can't bind port %d\n!\n", port);
178 goto out;
179 }
180 evconnlistener_set_error_cb(listener, accept_error_cb);
181
182 out:
183 *sess=(void*)s;
184 return ret;
185 }
186
187 static int serial2tcp_add_pads(void *sess, struct pad_list_s *plist)
188 {
189 int ret = RC_OK;
190 struct session_s *s=(struct session_s*)sess;
191 struct pad_s *pads;
192 if(!sess || !plist) {
193 ret = RC_INVARG;
194 goto out;
195 }
196 pads = plist->pads;
197 if(!strcmp(plist->name, "serial")) {
198 litex_sim_module_pads_get(pads, "sink_data", (void**)&s->rx);
199 litex_sim_module_pads_get(pads, "sink_valid", (void**)&s->rx_valid);
200 litex_sim_module_pads_get(pads, "sink_ready", (void**)&s->rx_ready);
201 litex_sim_module_pads_get(pads, "source_data", (void**)&s->tx);
202 litex_sim_module_pads_get(pads, "source_valid", (void**)&s->tx_valid);
203 litex_sim_module_pads_get(pads, "source_ready", (void**)&s->tx_ready);
204 }
205
206 if(!strcmp(plist->name, "sys_clk"))
207 litex_sim_module_pads_get(pads, "sys_clk", (void**)&s->sys_clk);
208
209 out:
210 return ret;
211
212 }
213 static int serial2tcp_tick(void *sess, uint64_t time_ps)
214 {
215 static struct clk_edge_t edge;
216 char c;
217 int ret = RC_OK;
218
219 struct session_s *s = (struct session_s*)sess;
220 if(!clk_pos_edge(&edge, *s->sys_clk)) {
221 return RC_OK;
222 }
223
224 *s->tx_ready = 1;
225 if(s->fd && *s->tx_valid) {
226 c = *s->tx;
227 if(-1 ==write(s->fd, &c, 1)) {
228 eprintf("Error writing on socket\n");
229 ret = RC_ERROR;
230 goto out;
231 }
232 }
233
234 *s->rx_valid=0;
235 if(s->datalen) {
236 *s->rx=s->databuf[s->data_start];
237 s->data_start = (s->data_start + 1) % 2048;
238 s->datalen--;
239 *s->rx_valid=1;
240 }
241
242 out:
243 return ret;
244 }
245
246 static struct ext_module_s ext_mod = {
247 "serial2tcp",
248 serial2tcp_start,
249 serial2tcp_new,
250 serial2tcp_add_pads,
251 NULL,
252 serial2tcp_tick
253 };
254
255 int litex_sim_ext_module_init(int (*register_module)(struct ext_module_s *))
256 {
257 int ret = RC_OK;
258 ret = register_module(&ext_mod);
259 return ret;
260 }