diff options
| -rw-r--r-- | altosui/AltosBTDevice.java | 142 | ||||
| -rw-r--r-- | altosui/AltosEepromDownload.java | 1 | ||||
| -rw-r--r-- | altosui/Makefile.am | 1 | ||||
| -rw-r--r-- | altosui/libaltos/Makefile.am | 2 | ||||
| -rw-r--r-- | altosui/libaltos/cjnitest.c | 26 | ||||
| -rw-r--r-- | altosui/libaltos/libaltos.c | 574 | ||||
| -rw-r--r-- | altosui/libaltos/libaltos.h | 21 | 
7 files changed, 543 insertions, 224 deletions
| diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java new file mode 100644 index 00000000..8eb18bb9 --- /dev/null +++ b/altosui/AltosBTDevice.java @@ -0,0 +1,142 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package altosui; +import java.lang.*; +import java.util.*; +import libaltosJNI.*; + +public class AltosBTDevice extends altos_bt_device { + +	static public boolean initialized = false; +	static public boolean loaded_library = false; + +	public static boolean load_library() { +		if (!initialized) { +			try { +				System.loadLibrary("altos"); +				libaltos.altos_init(); +				loaded_library = true; +			} catch (UnsatisfiedLinkError e) { +				loaded_library = false; +			} +			initialized = true; +		} +		return loaded_library; +	} + +	static String bt_product_telebt() { +		if (load_library()) +			return libaltosConstants.BLUETOOTH_PRODUCT_TELEBT; +		return "TeleBT"; +	} + +	public final static String bt_product_telebt = bt_product_telebt(); +	public final static String bt_product_any = "Any"; +	public final static String bt_product_basestation = "Basestation"; + +	public String getProduct() { +		String	name = getName(); +		if (name == null) +			return "Altus Metrum"; +		int	dash = name.lastIndexOf("-"); +		if (dash < 0) +			return name; +		return name.substring(0,dash); +	} + +	public int getSerial() { +		String name = getName(); +		if (name == null) +			return 0; +		int dash = name.lastIndexOf("-"); +		if (dash < 0 || dash >= name.length()) +			return 0; +		String sn = name.substring(dash + 1, name.length()); +		try { +			return Integer.parseInt(sn); +		} catch (NumberFormatException ne) { +			return 0; +		} +	} + +	public String toString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%-20.20s %4d %s", +				     getProduct(), getSerial(), getAddr()); +	} + +	public String toShortString() { +		String	name = getName(); +		if (name == null) +			name = "Altus Metrum"; +		return String.format("%s %d %s", +				     getProduct(), getSerial(), getAddr()); + +	} + +	public boolean isAltusMetrum() { +		if (getName().startsWith(bt_product_telebt)) +			return true; +		return false; +	} + +	public boolean matchProduct(String want_product) { + +		if (!isAltusMetrum()) +			return false; + +		if (want_product.equals(bt_product_any)) +			return true; + +		if (want_product.equals(bt_product_basestation)) +			return matchProduct(bt_product_telebt); + +		if (want_product.equals(getProduct())) +			return true; + +		return false; +	} + +	static AltosBTDevice[] list(String product) { +		if (!load_library()) +			return null; + +		SWIGTYPE_p_altos_bt_list list = libaltos.altos_bt_list_start(); + +		ArrayList<AltosBTDevice> device_list = new ArrayList<AltosBTDevice>(); +		if (list != null) { +			SWIGTYPE_p_altos_file file; + +			for (;;) { +				AltosBTDevice device = new AltosBTDevice(); +				if (libaltos.altos_bt_list_next(list, device) == 0) +					break; +				if (device.matchProduct(product)) +					device_list.add(device); +			} +			libaltos.altos_bt_list_finish(list); +		} + +		AltosBTDevice[] devices = new AltosBTDevice[device_list.size()]; +		for (int i = 0; i < device_list.size(); i++) +			devices[i] = device_list.get(i); +		return devices; +	} +}
\ No newline at end of file diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java index fad16460..5c704968 100644 --- a/altosui/AltosEepromDownload.java +++ b/altosui/AltosEepromDownload.java @@ -158,6 +158,7 @@ public class AltosEepromDownload implements Runnable {  					r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, s, 0);  					if (s == Altos.ao_flight_landed)  						done = true; +					state = s;  					any_valid = true;  				} else {  					if (v != 0xffff) diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 01fe50c8..5b11d1b0 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -26,6 +26,7 @@ altosui_JAVA = \  	AltosDescent.java \  	AltosDeviceDialog.java \  	AltosDevice.java \ +	AltosBTDevice.java \  	AltosDisplayThread.java \  	AltosEepromChunk.java \  	AltosEepromDelete.java \ diff --git a/altosui/libaltos/Makefile.am b/altosui/libaltos/Makefile.am index 388d2104..3f5f3ee2 100644 --- a/altosui/libaltos/Makefile.am +++ b/altosui/libaltos/Makefile.am @@ -16,7 +16,7 @@ noinst_PROGRAMS=cjnitest  cjnitest_LDADD=libaltos.la -LIBS= +LIBS=-lbluetooth  HFILES=libaltos.h diff --git a/altosui/libaltos/cjnitest.c b/altosui/libaltos/cjnitest.c index c6d6e069..79561643 100644 --- a/altosui/libaltos/cjnitest.c +++ b/altosui/libaltos/cjnitest.c @@ -14,6 +14,8 @@ main ()  {  	struct altos_device	device;  	struct altos_list	*list; +	struct altos_bt_device	bt_device; +	struct altos_bt_list	*bt_list;  	altos_init();  	list = altos_list_start(); @@ -39,5 +41,29 @@ main ()  		altos_close(file);  	}  	altos_list_finish(list); +	bt_list = altos_bt_list_start(); +	while (altos_bt_list_next(bt_list, &bt_device)) { +		printf ("%s %s\n", bt_device.name, bt_device.addr); +		if (strncmp(bt_device.name, "TeleBT", 6) == 0) { +			struct altos_file	*file; + +			int			c; +			file = altos_bt_open(&bt_device); +			if (!file) { +				printf("altos_bt_open failed\n"); +				continue; +			} +			altos_puts(file,"v\nc s\n"); +			altos_flush(file); +			while ((c = altos_getchar(file, 100)) >= 0) { +				putchar(c); +			} +			if (c != LIBALTOS_TIMEOUT) +				printf("getchar returns %d\n", c); +			altos_close(file); +		} +	} +	altos_bt_list_finish(bt_list);  	altos_fini(); +	return 0;  } diff --git a/altosui/libaltos/libaltos.c b/altosui/libaltos/libaltos.c index 465f0ac8..13635a0d 100644 --- a/altosui/libaltos/libaltos.c +++ b/altosui/libaltos/libaltos.c @@ -56,6 +56,230 @@ altos_strndup (const char *s, size_t n)  #define altos_strndup strndup  #endif +#ifdef POSIX_TTY + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <errno.h> + +#define USB_BUF_SIZE	64 + +struct altos_file { +	int				fd; +#ifdef USE_POLL +	int				pipe[2]; +#else +	int				out_fd; +#endif +	unsigned char			out_data[USB_BUF_SIZE]; +	int				out_used; +	unsigned char			in_data[USB_BUF_SIZE]; +	int				in_used; +	int				in_read; +}; + +PUBLIC struct altos_file * +altos_open(struct altos_device *device) +{ +	struct altos_file	*file = calloc (sizeof (struct altos_file), 1); +	int			ret; +	struct termios		term; + +	if (!file) +		return NULL; + +	file->fd = open(device->path, O_RDWR | O_NOCTTY); +	if (file->fd < 0) { +		perror(device->path); +		free(file); +		return NULL; +	} +#ifdef USE_POLL +	pipe(file->pipe); +#else +	file->out_fd = open(device->path, O_RDWR | O_NOCTTY); +	if (file->out_fd < 0) { +		perror(device->path); +		close(file->fd); +		free(file); +		return NULL; +	} +#endif +	ret = tcgetattr(file->fd, &term); +	if (ret < 0) { +		perror("tcgetattr"); +		close(file->fd); +#ifndef USE_POLL +		close(file->out_fd); +#endif +		free(file); +		return NULL; +	} +	cfmakeraw(&term); +#ifdef USE_POLL +	term.c_cc[VMIN] = 1; +	term.c_cc[VTIME] = 0; +#else +	term.c_cc[VMIN] = 0; +	term.c_cc[VTIME] = 1; +#endif +	ret = tcsetattr(file->fd, TCSAFLUSH, &term); +	if (ret < 0) { +		perror("tcsetattr"); +		close(file->fd); +#ifndef USE_POLL +		close(file->out_fd); +#endif +		free(file); +		return NULL; +	} +	return file; +} + +PUBLIC void +altos_close(struct altos_file *file) +{ +	if (file->fd != -1) { +		int	fd = file->fd; +		file->fd = -1; +#ifdef USE_POLL +		write(file->pipe[1], "\r", 1); +#else +		close(file->out_fd); +		file->out_fd = -1; +#endif +		close(fd); +	} +} + +PUBLIC void +altos_free(struct altos_file *file) +{ +	altos_close(file); +	free(file); +} + +PUBLIC int +altos_flush(struct altos_file *file) +{ +	if (file->out_used && 0) { +		printf ("flush \""); +		fwrite(file->out_data, 1, file->out_used, stdout); +		printf ("\"\n"); +	} +	while (file->out_used) { +		int	ret; + +		if (file->fd < 0) +			return -EBADF; +#ifdef USE_POLL +		ret = write (file->fd, file->out_data, file->out_used); +#else +		ret = write (file->out_fd, file->out_data, file->out_used); +#endif +		if (ret < 0) +			return -errno; +		if (ret) { +			memmove(file->out_data, file->out_data + ret, +				file->out_used - ret); +			file->out_used -= ret; +		} +	} +	return 0; +} + +PUBLIC int +altos_putchar(struct altos_file *file, char c) +{ +	int	ret; + +	if (file->out_used == USB_BUF_SIZE) { +		ret = altos_flush(file); +		if (ret) { +			return ret; +		} +	} +	file->out_data[file->out_used++] = c; +	ret = 0; +	if (file->out_used == USB_BUF_SIZE) +		ret = altos_flush(file); +	return 0; +} + +#ifdef USE_POLL +#include <poll.h> +#endif + +static int +altos_fill(struct altos_file *file, int timeout) +{ +	int		ret; +#ifdef USE_POLL +	struct pollfd	fd[2]; +#endif + +	if (timeout == 0) +		timeout = -1; +	while (file->in_read == file->in_used) { +		if (file->fd < 0) +			return LIBALTOS_ERROR; +#ifdef USE_POLL +		fd[0].fd = file->fd; +		fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; +		fd[1].fd = file->pipe[0]; +		fd[1].events = POLLIN; +		ret = poll(fd, 2, timeout); +		if (ret < 0) { +			perror("altos_getchar"); +			return LIBALTOS_ERROR; +		} +		if (ret == 0) +			return LIBALTOS_TIMEOUT; + +		if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL)) +			return LIBALTOS_ERROR; +		if (fd[0].revents & POLLIN) +#endif +		{ +			ret = read(file->fd, file->in_data, USB_BUF_SIZE); +			if (ret < 0) { +				perror("altos_getchar"); +				return LIBALTOS_ERROR; +			} +			file->in_read = 0; +			file->in_used = ret; +#ifndef USE_POLL +			if (ret == 0 && timeout > 0) +				return LIBALTOS_TIMEOUT; +#endif +		} +	} +	if (file->in_used && 0) { +		printf ("fill \""); +		fwrite(file->in_data, 1, file->in_used, stdout); +		printf ("\"\n"); +	} +	return 0; +} + +PUBLIC int +altos_getchar(struct altos_file *file, int timeout) +{ +	int	ret; +	while (file->in_read == file->in_used) { +		if (file->fd < 0) +			return LIBALTOS_ERROR; +		ret = altos_fill(file, timeout); +		if (ret) +			return ret; +	} +	return file->in_data[file->in_read++]; +} + +#endif /* POSIX_TTY */ +  /*   * Scan for Altus Metrum devices by looking through /sys   */ @@ -68,6 +292,10 @@ altos_strndup (const char *s, size_t n)  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/rfcomm.h>  static char *  cc_fullname (char *dir, char *file) @@ -354,6 +582,129 @@ altos_list_finish(struct altos_list *usbdevs)  	free(usbdevs);  } +struct altos_bt_list { +	inquiry_info	*ii; +	int		sock; +	int		dev_id; +	int		rsp; +	int		num_rsp; +}; + +#define INQUIRY_MAX_RSP	255 +#define INQUIRY_LEN	8 + +struct altos_bt_list * +altos_bt_list_start(void) +{ +	struct altos_bt_list	*bt_list; + +	bt_list = calloc(1, sizeof (struct altos_bt_list)); +	if (!bt_list) +		goto no_bt_list; + +	bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info)); +	if (!bt_list->ii) +		goto no_ii; +	bt_list->dev_id = hci_get_route(NULL); +	if (bt_list->dev_id < 0) +		goto no_dev_id; + +	bt_list->sock = hci_open_dev(bt_list->dev_id); +	if (bt_list->sock < 0) +		goto no_sock; + +	bt_list->num_rsp = hci_inquiry(bt_list->dev_id, +				       INQUIRY_LEN, +				       INQUIRY_MAX_RSP, +				       NULL, +				       &bt_list->ii, +				       IREQ_CACHE_FLUSH); +	if (bt_list->num_rsp < 0) +		goto no_rsp; + +	bt_list->rsp = 0; +	return bt_list; + +no_rsp: +	close(bt_list->sock); +no_sock: +no_dev_id: +	free(bt_list->ii); +no_ii: +	free(bt_list); +no_bt_list: +	return NULL; +} + +int +altos_bt_list_next(struct altos_bt_list *bt_list, +		   struct altos_bt_device *device) +{ +	inquiry_info	*ii; + +	if (bt_list->rsp >= bt_list->num_rsp) +		return 0; + +	ii = &bt_list->ii[bt_list->rsp]; +	ba2str(&ii->bdaddr, device->addr); +	memset(&device->name, '\0', sizeof (device->name)); +	if (hci_read_remote_name(bt_list->sock, &ii->bdaddr, +				 sizeof (device->name), +				 device->name, 0) < 0) { +		strcpy(device->name, "[unknown]"); +	} +	bt_list->rsp++; +	return 1; +} + +void +altos_bt_list_finish(struct altos_bt_list *bt_list) +{ +	close(bt_list->sock); +	free(bt_list->ii); +	free(bt_list); +} + +struct altos_file * +altos_bt_open(struct altos_bt_device *device) +{ +	struct sockaddr_rc addr = { 0 }; +	int	s, status; +	struct altos_file *file; + +	file = calloc(1, sizeof (struct altos_file)); +	if (!file) +		goto no_file; +	file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); +	if (file->fd < 0) +		goto no_sock; + +	addr.rc_family = AF_BLUETOOTH; +	addr.rc_channel = 1; +	str2ba(device->addr, &addr.rc_bdaddr); + +	status = connect(file->fd, +			 (struct sockaddr *)&addr, +			 sizeof(addr)); +	if (status < 0) { +		perror("connect"); +		goto no_link; +	} + +#ifdef USE_POLL +	pipe(file->pipe); +#else +	file->out_fd = dup(file->fd); +#endif +	return file; +no_link: +	close(s); +no_sock: +	free(file); +no_file: +	return NULL; +} +  #endif  #ifdef DARWIN @@ -468,229 +819,6 @@ altos_list_finish(struct altos_list *list)  #endif -#ifdef POSIX_TTY - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <termios.h> -#include <errno.h> - -#define USB_BUF_SIZE	64 - -struct altos_file { -	int				fd; -#ifdef USE_POLL -	int				pipe[2]; -#else -	int				out_fd; -#endif -	unsigned char			out_data[USB_BUF_SIZE]; -	int				out_used; -	unsigned char			in_data[USB_BUF_SIZE]; -	int				in_used; -	int				in_read; -}; - -PUBLIC struct altos_file * -altos_open(struct altos_device *device) -{ -	struct altos_file	*file = calloc (sizeof (struct altos_file), 1); -	int			ret; -	struct termios		term; - -	if (!file) -		return NULL; - -	file->fd = open(device->path, O_RDWR | O_NOCTTY); -	if (file->fd < 0) { -		perror(device->path); -		free(file); -		return NULL; -	} -#ifdef USE_POLL -	pipe(file->pipe); -#else -	file->out_fd = open(device->path, O_RDWR | O_NOCTTY); -	if (file->out_fd < 0) { -		perror(device->path); -		close(file->fd); -		free(file); -		return NULL; -	} -#endif -	ret = tcgetattr(file->fd, &term); -	if (ret < 0) { -		perror("tcgetattr"); -		close(file->fd); -#ifndef USE_POLL -		close(file->out_fd); -#endif -		free(file); -		return NULL; -	} -	cfmakeraw(&term); -#ifdef USE_POLL -	term.c_cc[VMIN] = 1; -	term.c_cc[VTIME] = 0; -#else -	term.c_cc[VMIN] = 0; -	term.c_cc[VTIME] = 1; -#endif -	ret = tcsetattr(file->fd, TCSAFLUSH, &term); -	if (ret < 0) { -		perror("tcsetattr"); -		close(file->fd); -#ifndef USE_POLL -		close(file->out_fd); -#endif -		free(file); -		return NULL; -	} -	return file; -} - -PUBLIC void -altos_close(struct altos_file *file) -{ -	if (file->fd != -1) { -		int	fd = file->fd; -		file->fd = -1; -#ifdef USE_POLL -		write(file->pipe[1], "\r", 1); -#else -		close(file->out_fd); -		file->out_fd = -1; -#endif -		close(fd); -	} -} - -PUBLIC void -altos_free(struct altos_file *file) -{ -	altos_close(file); -	free(file); -} - -PUBLIC int -altos_flush(struct altos_file *file) -{ -	if (file->out_used && 0) { -		printf ("flush \""); -		fwrite(file->out_data, 1, file->out_used, stdout); -		printf ("\"\n"); -	} -	while (file->out_used) { -		int	ret; - -		if (file->fd < 0) -			return -EBADF; -#ifdef USE_POLL -		ret = write (file->fd, file->out_data, file->out_used); -#else -		ret = write (file->out_fd, file->out_data, file->out_used); -#endif -		if (ret < 0) -			return -errno; -		if (ret) { -			memmove(file->out_data, file->out_data + ret, -				file->out_used - ret); -			file->out_used -= ret; -		} -	} -	return 0; -} - -PUBLIC int -altos_putchar(struct altos_file *file, char c) -{ -	int	ret; - -	if (file->out_used == USB_BUF_SIZE) { -		ret = altos_flush(file); -		if (ret) { -			return ret; -		} -	} -	file->out_data[file->out_used++] = c; -	ret = 0; -	if (file->out_used == USB_BUF_SIZE) -		ret = altos_flush(file); -	return 0; -} - -#ifdef USE_POLL -#include <poll.h> -#endif - -static int -altos_fill(struct altos_file *file, int timeout) -{ -	int		ret; -#ifdef USE_POLL -	struct pollfd	fd[2]; -#endif - -	if (timeout == 0) -		timeout = -1; -	while (file->in_read == file->in_used) { -		if (file->fd < 0) -			return LIBALTOS_ERROR; -#ifdef USE_POLL -		fd[0].fd = file->fd; -		fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; -		fd[1].fd = file->pipe[0]; -		fd[1].events = POLLIN; -		ret = poll(fd, 2, timeout); -		if (ret < 0) { -			perror("altos_getchar"); -			return LIBALTOS_ERROR; -		} -		if (ret == 0) -			return LIBALTOS_TIMEOUT; - -		if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL)) -			return LIBALTOS_ERROR; -		if (fd[0].revents & POLLIN) -#endif -		{ -			ret = read(file->fd, file->in_data, USB_BUF_SIZE); -			if (ret < 0) { -				perror("altos_getchar"); -				return LIBALTOS_ERROR; -			} -			file->in_read = 0; -			file->in_used = ret; -#ifndef USE_POLL -			if (ret == 0 && timeout > 0) -				return LIBALTOS_TIMEOUT; -#endif -		} -	} -	if (file->in_used && 0) { -		printf ("fill \""); -		fwrite(file->in_data, 1, file->in_used, stdout); -		printf ("\"\n"); -	} -	return 0; -} - -PUBLIC int -altos_getchar(struct altos_file *file, int timeout) -{ -	int	ret; -	while (file->in_read == file->in_used) { -		if (file->fd < 0) -			return LIBALTOS_ERROR; -		ret = altos_fill(file, timeout); -		if (ret) -			return ret; -	} -	return file->in_data[file->in_read++]; -} - -#endif /* POSIX_TTY */  #ifdef WINDOWS diff --git a/altosui/libaltos/libaltos.h b/altosui/libaltos/libaltos.h index 0e5691cb..9c3f9655 100644 --- a/altosui/libaltos/libaltos.h +++ b/altosui/libaltos/libaltos.h @@ -58,6 +58,15 @@ struct altos_device {  	//%mutable;  }; +#define BLUETOOTH_PRODUCT_TELEBT	"TeleBT" + +struct altos_bt_device { +	//%immutable; +	char				name[256]; +	char				addr[20]; +	//%mutable; +}; +  #define LIBALTOS_SUCCESS	0  #define LIBALTOS_ERROR		-1  #define LIBALTOS_TIMEOUT	-2 @@ -100,4 +109,16 @@ altos_flush(struct altos_file *file);  PUBLIC int  altos_getchar(struct altos_file *file, int timeout); +PUBLIC struct altos_bt_list * +altos_bt_list_start(void); + +PUBLIC int +altos_bt_list_next(struct altos_bt_list *list, struct altos_bt_device *device); + +PUBLIC void +altos_bt_list_finish(struct altos_bt_list *list); + +PUBLIC struct altos_file * +altos_bt_open(struct altos_bt_device *device); +  #endif /* _LIBALTOS_H_ */ | 
