1/*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <sys/ioctl.h>
31#include <errno.h> // required on BeOS R5
32#include <OS.h>
33
34#include "DVBCard.h"
35
36
37DVBCard::DVBCard(const char *path)
38 :	fInitStatus(B_OK)
39 ,	fDev(-1)
40{
41	printf("DVBCard opening %s\n", path);
42
43	fDev = open(path, O_RDWR);
44	if (fDev < 0) {
45		printf("DVBCard opening %s failed\n", path);
46		fInitStatus = B_ERROR;
47		return;
48	}
49
50	dvb_frequency_info_t info;
51	if (do_ioctl(fDev, DVB_GET_FREQUENCY_INFO, &info) < 0) {
52		printf("DVB_GET_FREQUENCY_INFO failed with error %s\n", strerror(errno));
53//		close(fDev);
54//		fDev = -1;
55//		return;
56	}
57
58	fFreqMin  = info.frequency_min;
59	fFreqMax  = info.frequency_max;
60	fFreqStep = info.frequency_step;
61
62	fCaptureActive = false;
63}
64
65
66DVBCard::~DVBCard()
67{
68	if (fDev > 0)
69		close(fDev);
70}
71
72
73status_t
74DVBCard::InitCheck()
75{
76	return fInitStatus;
77}
78
79
80status_t
81DVBCard::GetCardType(dvb_type_t *type)
82{
83	dvb_interface_info_t info;
84
85	if (do_ioctl(fDev, DVB_GET_INTERFACE_INFO, &info) < 0) {
86		printf("DVB_GET_INTERFACE_INFO failed with error %s\n", strerror(errno));
87		return errno;
88	}
89
90	if (info.version < 1) {
91		printf("DVBCard::GetCardInfo wrong API version\n");
92		return B_ERROR;
93	}
94
95	*type = info.type;
96	return B_OK;
97}
98
99
100status_t
101DVBCard::GetCardInfo(char *_name, int max_name_len, char *_info, int max_info_len)
102{
103	dvb_interface_info_t info;
104
105	if (do_ioctl(fDev, DVB_GET_INTERFACE_INFO, &info) < 0) {
106		printf("DVB_GET_INTERFACE_INFO failed with error %s\n", strerror(errno));
107		return errno;
108	}
109
110//	strlcpy(_name, info.name, max_name_len);
111//	strlcpy(_info, info.info, max_info_len);
112	strcpy(_name, info.name);
113	strcpy(_info, info.info);
114
115	if (info.version < 1) {
116		printf("DVBCard::GetCardInfo wrong API version\n");
117		return B_ERROR;
118	}
119
120	return B_OK;
121}
122
123
124status_t
125DVBCard::SetTuningParameter(const dvb_tuning_parameters_t& param)
126{
127	if (fDev < 0)
128		return B_NO_INIT;
129
130	printf("DVBCard::SetTuningParameter:\n");
131/*
132	printf("frequency %lld\n", param.frequency);
133	printf("inversion %d\n", param.inversion);
134	printf("bandwidth %d\n", param.bandwidth);
135	printf("modulation %d\n", param.modulation);
136	printf("hierarchy %d\n", param.hierarchy);
137	printf("code_rate_hp %d\n", param.code_rate_hp);
138	printf("code_rate_lp %d\n", param.code_rate_lp);
139	printf("transmission_mode %d\n", param.transmission_mode);
140	printf("guard_interval %d\n", param.guard_interval);
141	printf("symbolrate %d\n", param.symbolrate);
142	printf("polarity %d\n", param.polarity);
143	printf("agc_inversion %d\n", param.agc_inversion);
144*/
145	params = param;// XXX temporary!
146
147//	if (do_ioctl(fDev, DVB_SET_TUNING_PARAMETERS, const_cast<void *>(&param)) < 0) {
148//	if (do_ioctl(fDev, DVB_SET_TUNING_PARAMETERS, (void *)(&param)) < 0) {
149	if (ioctl(fDev, DVB_SET_TUNING_PARAMETERS, (void *)(&param)) < 0) {
150		printf("DVB_SET_TUNING_PARAMETERS failed with error %s\n", strerror(errno));
151		return errno;
152	}
153
154	dvb_status_t status;
155
156	bigtime_t start = system_time();
157	bool has_lock = false;
158	bool has_signal = false;
159	bool has_carrier = false;
160	do {
161		if (do_ioctl(fDev, DVB_GET_STATUS, &status) < 0) {
162			printf("DVB_GET_STATUS failed with error %s\n", strerror(errno));
163			return errno;
164		}
165		if (!has_signal && status & DVB_STATUS_SIGNAL) {
166			has_signal = true;
167			printf("got signal after %.6f\n", (system_time() - start) / 1e6);
168		}
169		if (!has_carrier && status & DVB_STATUS_CARRIER) {
170			has_carrier = true;
171			printf("got carrier after %.6f\n", (system_time() - start) / 1e6);
172		}
173		if (!has_lock && status & DVB_STATUS_LOCK) {
174			has_lock = true;
175			printf("got lock after %.6f\n", (system_time() - start) / 1e6);
176		}
177
178		if ((status & (DVB_STATUS_SIGNAL|DVB_STATUS_CARRIER|DVB_STATUS_LOCK)) == (DVB_STATUS_SIGNAL|DVB_STATUS_CARRIER|DVB_STATUS_LOCK))
179			break;
180		snooze(25000);
181	} while ((system_time() - start) < 5000000);
182
183
184	if ((status & (DVB_STATUS_SIGNAL|DVB_STATUS_CARRIER|DVB_STATUS_LOCK)) != (DVB_STATUS_SIGNAL|DVB_STATUS_CARRIER|DVB_STATUS_LOCK)) {
185		printf("DVB tuning failed! need these status flags: DVB_STATUS_SIGNAL, DVB_STATUS_CARRIER, DVB_STATUS_LOCK\n");
186		return B_ERROR;
187	}
188
189	return B_OK;
190}
191
192
193status_t
194DVBCard::GetTuningParameter(dvb_tuning_parameters_t *param)
195{
196	// XXX get from CARD
197	*param = params;
198	return B_OK;
199}
200
201
202status_t
203DVBCard::GetSignalInfo(uint32 *ss, uint32 *ber, uint32 *snr)
204{
205	if (do_ioctl(fDev, DVB_GET_SS, ss) < 0) {
206		printf("DVB_GET_SS failed with error %s\n", strerror(errno));
207		return errno;
208	}
209	if (do_ioctl(fDev, DVB_GET_BER, ber) < 0) {
210		printf("DVB_GET_BER failed with error %s\n", strerror(errno));
211		return errno;
212	}
213	if (do_ioctl(fDev, DVB_GET_SNR, snr) < 0) {
214		printf("DVB_GET_SNR failed with error %s\n", strerror(errno));
215		return errno;
216	}
217
218	printf("ss %08lx, ber %08lx, snr %08lx\n", *ss, *ber, *snr);
219	printf("ss %lu%%, ber %lu%%, snr %lu%%\n", *ss / (0xffffffff / 100), *ber / (0xffffffff / 100), *snr / (0xffffffff / 100));
220	return B_OK;
221}
222
223
224status_t
225DVBCard::CaptureStart()
226{
227	printf("DVBCard::CaptureStart\n");
228
229	if (fCaptureActive) {
230		printf("CaptureStart already called, doing nothing\n");
231		return B_OK;
232	}
233
234	if (do_ioctl(fDev, DVB_START_CAPTURE, 0) < 0) {
235		printf("DVB_START_CAPTURE failed with error %s\n", strerror(errno));
236		return errno;
237	}
238
239	fCaptureActive = true;
240	return B_OK;
241}
242
243
244status_t
245DVBCard::CaptureStop()
246{
247	printf("DVBCard::CaptureStop\n");
248
249	if (!fCaptureActive) {
250		printf("CaptureStop already called, doing nothing\n");
251		return B_OK;
252	}
253
254	if (do_ioctl(fDev, DVB_STOP_CAPTURE, 0) < 0) {
255		printf("DVB_STOP_CAPTURE failed with error %s\n", strerror(errno));
256		return errno;
257	}
258
259	fCaptureActive = false;
260	return B_OK;
261}
262
263
264status_t
265DVBCard::Capture(void **data, size_t *size, bigtime_t *end_time)
266{
267	dvb_capture_t cap;
268
269	if (ioctl(fDev, DVB_CAPTURE, &cap) < 0)
270		return errno;
271
272	*data	  = cap.data;
273	*size	  = cap.size;
274	*end_time = cap.end_time;
275
276	return B_OK;
277}
278
279
280int
281DVBCard::do_ioctl(int fDev, ulong op, void *arg)
282{
283	int res = 0; // silence stupid compiler warning
284	int i;
285	for (i = 0; i < 20; i++) {
286		res = ioctl(fDev, op, arg);
287		if (res >= 0)
288			break;
289	}
290	if (i != 0)	printf("ioctl %lx repeated %d times\n", op, i);
291	return res;
292}
293