File: hw_udp.c

package info (click to toggle)
lirc 0.7.1pre2-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,852 kB
  • ctags: 2,924
  • sloc: ansic: 31,205; sh: 12,021; makefile: 631
file content (185 lines) | stat: -rw-r--r-- 4,286 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/****************************************************************************
 ** hw_udp.c ****************************************************************
 ****************************************************************************
 *
 * receive mode2 input via UDP
 * 
 * Copyright (C) 2002 Jim Paris <jim@jtan.com>
 *
 * Distribute under GPL version 2 or later.
 *
 * Received UDP packets consist of some number of LE 16-bit integers.
 * The high bit signifies whether the received signal was high or low;
 * the low 15 bits specify the number of 1/16384-second intervals the
 * signal lasted.
 *
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <errno.h>

#include "hardware.h"
#include "ir_remote.h"
#include "lircd.h"
#include "receive.h"
#include "transmit.h"
#include "hw_default.h"

static int zerofd;       /* /dev/zero */
static int sockfd;       /* the socket */

int udp_init()
{
	int port;
	struct sockaddr_in addr;

	logprintf(LOG_INFO,"Initializing UDP",hw.device);
	
	init_rec_buffer();
	
	port=atoi(hw.device);
	if(port==0) {
		logprintf(LOG_ERR,"invalid port: %s",hw.device);
		return 0;
	}

	/* hw.fd needs to point somewhere when we have extra data */
	if((zerofd=open("/dev/zero",O_RDONLY))<0) {
		logprintf(LOG_ERR,"can't open /dev/zero: %s",
			  strerror(errno));
		return 0;
	}

	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) {
		logprintf(LOG_ERR,"error creating socket: %s",
			  strerror(errno));
		close(zerofd);
		return 0;
	}
	
	addr.sin_family      = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port        = htons(port);
	
	if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0) {
		logprintf(LOG_ERR,"can't bind socket to port %d: %s",
			  port,strerror(errno));
		close(sockfd);
		close(zerofd);
		return 0;
	}
	
	logprintf(LOG_INFO,"Listening on port %d/udp",port);

	hw.fd=sockfd;

	return(1);
}

int udp_deinit(void)
{
	close(sockfd);
	close(zerofd);
	hw.fd=-1;
	return(1);
}

char *udp_rec(struct ir_remote *remotes)
{
	if(!clear_rec_buffer()) return(NULL);
	return(decode_all(remotes));
}

int udp_decode(struct ir_remote *remote,
	       ir_code *prep,ir_code *codep,ir_code *postp,
	       int *repeat_flagp,lirc_t *remaining_gapp)
{
	return(receive_decode(remote,prep,codep,postp,
			      repeat_flagp,remaining_gapp));
}

lirc_t udp_readdata(lirc_t timeout)
{
	static u_int8_t buffer[8192];
	static int buflen=0;
	static int bufptr=0;
	lirc_t data;
	u_int8_t packed[2];
	u_int32_t tmp;
	fd_set rfd;
	struct timeval tv;

	/* Assume buffer is empty; LIRC should select on the socket */
	hw.fd=sockfd;

	/* If buffer is empty, get data into it */
	if((bufptr+2)>buflen) 
	{
		FD_ZERO(&rfd);
		FD_SET(sockfd,&rfd);
		tv.tv_sec=0;
		tv.tv_usec=timeout;
		if(select(sockfd+1,&rfd,NULL,NULL,&tv)!=1) 
			return 0;
		if((buflen=recv(sockfd,&buffer,sizeof(buffer),0))<0)
		{
			logprintf(LOG_INFO,"Error reading from UDP socket");
			return 0;
		}
		if(buflen&1) 
			buflen--;
		if(buflen==0)
			return 0;
		bufptr=0;
	}

	/* Read as 2 bytes to avoid endian-ness issues */
	packed[0]=buffer[bufptr++];
	packed[1]=buffer[bufptr++];

	/* TODO: This assumes the receiver is active low.  Should 
	   be specified by user, or autodetected.  */
	data = (packed[1] & 0x80) ? 0 : PULSE_BIT;

	/* Convert 1/16384-seconds to microseconds */
	tmp = (((u_int32_t)packed[1])<<8) | packed[0];
	/* tmp = ((tmp & 0x7FFF) * 1000000) / 16384; */
	/* prevent integer overflow: */
	tmp = ((tmp & 0x7FFF) * 15625) / 256;

	data |= tmp & PULSE_MASK;

	/* If our buffer still has data, give LIRC /dev/zero to select on */
	if((bufptr+2)<=buflen)
		hw.fd=zerofd;
	
	return(data);
}

struct hardware hw_udp=
{
	"8765",	    	    /* "device" (port) */
	-1,                 /* fd (socket) */
	LIRC_CAN_REC_MODE2, /* features */
	0,                  /* send_mode */
	LIRC_MODE_MODE2,    /* rec_mode */
	0,                  /* code_length */
	udp_init,	    /* init_func */
	NULL,		    /* config_func */
	udp_deinit,         /* deinit_func */
	NULL,		    /* send_func */
	udp_rec,            /* rec_func */
	udp_decode,         /* decode_func */
	udp_readdata,       /* readdata */
	"udp"
};