1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014-2017 Kumar Abhishek <abhishek@theembeddedkitchen.net>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #ifdef _WIN32
25 #define _WIN32_WINNT 0x0501
26 #include <winsock2.h>
27 #include <ws2tcpip.h>
28 #else
29 #include <sys/socket.h>
30 #endif
31 #include <errno.h>
32 #include "protocol.h"
33 #include "beaglelogic.h"
34 
35 /* Define data packet size independent of packet (bufunitsize bytes) size
36  * from the BeagleLogic kernel module */
37 #define PACKET_SIZE	(512 * 1024)
38 
39 /* This implementation is zero copy from the libsigrok side.
40  * It does not copy any data, just passes a pointer from the mmap'ed
41  * kernel buffers appropriately. It is up to the application which is
42  * using libsigrok to decide how to deal with the data.
43  */
beaglelogic_native_receive_data(int fd,int revents,void * cb_data)44 SR_PRIV int beaglelogic_native_receive_data(int fd, int revents, void *cb_data)
45 {
46 	const struct sr_dev_inst *sdi;
47 	struct dev_context *devc;
48 	struct sr_datafeed_packet packet;
49 	struct sr_datafeed_logic logic;
50 
51 	int trigger_offset;
52 	int pre_trigger_samples;
53 	uint32_t packetsize;
54 	uint64_t bytes_remaining;
55 
56 	if (!(sdi = cb_data) || !(devc = sdi->priv))
57 		return TRUE;
58 
59 	packetsize = PACKET_SIZE;
60 	logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
61 
62 	if (revents == G_IO_IN) {
63 		sr_info("In callback G_IO_IN, offset=%d", devc->offset);
64 
65 		bytes_remaining = (devc->limit_samples * logic.unitsize) -
66 				devc->bytes_read;
67 
68 		/* Configure data packet */
69 		packet.type = SR_DF_LOGIC;
70 		packet.payload = &logic;
71 		logic.data = devc->sample_buf + devc->offset;
72 		logic.length = MIN(packetsize, bytes_remaining);
73 
74 		if (devc->trigger_fired) {
75 			/* Send the incoming transfer to the session bus. */
76 			sr_session_send(sdi, &packet);
77 		} else {
78 			/* Check for trigger */
79 			trigger_offset = soft_trigger_logic_check(devc->stl,
80 					logic.data, packetsize, &pre_trigger_samples);
81 			if (trigger_offset > -1) {
82 				devc->bytes_read += pre_trigger_samples * logic.unitsize;
83 				trigger_offset *= logic.unitsize;
84 				logic.length = MIN(packetsize - trigger_offset,
85 						bytes_remaining);
86 				logic.data += trigger_offset;
87 
88 				sr_session_send(sdi, &packet);
89 
90 				devc->trigger_fired = TRUE;
91 			}
92 		}
93 
94 		/* Move the read pointer forward */
95 		lseek(fd, packetsize, SEEK_CUR);
96 
97 		/* Update byte count and offset (roll over if needed) */
98 		devc->bytes_read += logic.length;
99 		if ((devc->offset += packetsize) >= devc->buffersize) {
100 			/* One shot capture, we abort and settle with less than
101 			 * the required number of samples */
102 			if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
103 				devc->offset = 0;
104 			else
105 				packetsize = 0;
106 		}
107 	}
108 
109 	/* EOF Received or we have reached the limit */
110 	if (devc->bytes_read >= devc->limit_samples * logic.unitsize ||
111 			packetsize == 0) {
112 		/* Send EOA Packet, stop polling */
113 		std_session_send_df_end(sdi);
114 		sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
115 	}
116 
117 	return TRUE;
118 }
119 
beaglelogic_tcp_receive_data(int fd,int revents,void * cb_data)120 SR_PRIV int beaglelogic_tcp_receive_data(int fd, int revents, void *cb_data)
121 {
122 	const struct sr_dev_inst *sdi;
123 	struct dev_context *devc;
124 	struct sr_datafeed_packet packet;
125 	struct sr_datafeed_logic logic;
126 
127 	int len;
128 	int pre_trigger_samples;
129 	int trigger_offset;
130 	uint32_t packetsize;
131 	uint64_t bytes_remaining;
132 
133 	if (!(sdi = cb_data) || !(devc = sdi->priv))
134 		return TRUE;
135 
136 	packetsize = TCP_BUFFER_SIZE;
137 	logic.unitsize = SAMPLEUNIT_TO_BYTES(devc->sampleunit);
138 
139 	if (revents == G_IO_IN) {
140 		sr_info("In callback G_IO_IN");
141 
142 		len = recv(fd, devc->tcp_buffer, TCP_BUFFER_SIZE, 0);
143 		if (len < 0) {
144 			sr_err("Receive error: %s", g_strerror(errno));
145 			return SR_ERR;
146 		}
147 
148 		packetsize = len;
149 
150 		bytes_remaining = (devc->limit_samples * logic.unitsize) -
151 				devc->bytes_read;
152 
153 		/* Configure data packet */
154 		packet.type = SR_DF_LOGIC;
155 		packet.payload = &logic;
156 		logic.data = devc->tcp_buffer;
157 		logic.length = MIN(packetsize, bytes_remaining);
158 
159 		if (devc->trigger_fired) {
160 			/* Send the incoming transfer to the session bus. */
161 			sr_session_send(sdi, &packet);
162 		} else {
163 			/* Check for trigger */
164 			trigger_offset = soft_trigger_logic_check(devc->stl,
165 					logic.data, packetsize, &pre_trigger_samples);
166 			if (trigger_offset > -1) {
167 				devc->bytes_read += pre_trigger_samples * logic.unitsize;
168 				trigger_offset *= logic.unitsize;
169 				logic.length = MIN(packetsize - trigger_offset,
170 						bytes_remaining);
171 				logic.data += trigger_offset;
172 
173 				sr_session_send(sdi, &packet);
174 
175 				devc->trigger_fired = TRUE;
176 			}
177 		}
178 
179 		/* Update byte count and offset (roll over if needed) */
180 		devc->bytes_read += logic.length;
181 		if ((devc->offset += packetsize) >= devc->buffersize) {
182 			/* One shot capture, we abort and settle with less than
183 			 * the required number of samples */
184 			if (devc->triggerflags == BL_TRIGGERFLAGS_CONTINUOUS)
185 				devc->offset = 0;
186 			else
187 				packetsize = 0;
188 		}
189 	}
190 
191 	/* EOF Received or we have reached the limit */
192 	if (devc->bytes_read >= devc->limit_samples * logic.unitsize ||
193 			packetsize == 0) {
194 		/* Send EOA Packet, stop polling */
195 		std_session_send_df_end(sdi);
196 		devc->beaglelogic->stop(devc);
197 
198 		/* Drain the receive buffer */
199 		beaglelogic_tcp_drain(devc);
200 
201 		sr_session_source_remove_pollfd(sdi->session, &devc->pollfd);
202 	}
203 
204 	return TRUE;
205 }
206