How to use netlink sockets for kernel - userspace communication Android - android

I'm trying to write kernel module for android to communicate with userspace Service so my app can display some information about the kernel. So far I've tried several examples I found on the web and none of them works. The idea is for kernel to send updates and service would then pick them up. ioctl is not a solution because the communication needs to be event driven, and initiated from kernel. C code for both jni and kernel module would be great if anyone knows how to do this.

Here's a code snippet that I've used (excluding error checking of return values for conciseness) where the netlink socket communication is driven by the kernel (i.e. the kernel is the sender, user program is the receiver).
Kernel module
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <string.h>
#define MY_GROUP 1
struct sock* socket;
struct sk_buff* socket_buff;
static void nl_receive_callback (struct sk_buff *skb)
{
nlmsg_free(skb);
}
static void kernel_send_nl_msg(void)
{
struct nlmsghdr *nlsk_mh;
char* msg = "hello kernel";
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);
socket_buff = nlmsg_new(256, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
NETLINK_CB(socket_buff).pid = 0; // kernel pid
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
return;
}
You'd fire this up as a result of your kernel event, e.g. in response to an ioctl or within your interrupt handling.
User Program
#include <sys/socket.h>
#include <linux/netlink.h>
#define MY_GROUP 1
void user_recieve_nl_msg(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(256));
memset(nl_msghdr, 0, NLMSG_SPACE(256));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(256);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
recvmsg(sock_fd, &msghdr, 0);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
print("Kernel message: %s\n", kernel_msg); // print to android logs
}
close(sock_fd);
}
I use nlmsg_multicast() in the kernel rather than nlmsg_unicast() because to do a unicast, the kernel module would need to know the process id of your user process (so you'd need to add some extra implementation there).
Hope that helps!

I have successfully used netlink socket to communicate between kernel and user-space in Android. To use socket in non-blocking mode use the fcntl and select call.

Related

Create UDP server using C++ to embed in cross platform iOS and Android app

I am developing a cross-platform mobile game (iOS and Android) using cocos2d-x.
Most of my code is written in C++, with OS specific code in Objective-C / Java / Swift using a bridge.
I was wondering if anyone has used any C++ library to host a UDP server within their app ?
EDIT: So far I have found many platform specific solutions (using Java for Android, and cocoaasync etc for iOS), but nothing specifically in C++ which has been used for a cross platform app.
Edit: I would prefer a solution without boost. Preferably something simple to include like adding a couple of files to a project.
You can most probably use Valve's GameNetworkingSockets, https://github.com/ValveSoftware/GameNetworkingSockets
They have very limited external dependencies, so you should be able to compile them for both iOS and Android
You can also take a look at this list: https://github.com/MFatihMAR/Awesome-Game-Networking, where there is a list of libraries that you can alternatively try.
You can use ASIO Standalone library. It is the same library available as boost/asio, but it doesn't require any other boost libraries. I have used boost/asio in exactly this type of project (Android/iOS) and it is by far the most superior solution.
Here is what I ended up with:
h file:
#include "Queue.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <array>
#include <iostream>
#include <thread>
using namespace std;
#define MAXBUFFER_SIZE 1024
class UDPServer {
public:
/**
* Constructor
*
* #port the port on which the UDP server is listening for packets.
*/
explicit UDPServer(unsigned short port);
/**
* Destructor
*/
~UDPServer() = default;
/**
* Setup the server.
*/
void setupServer();
/**
* Get a single message.
* For demonstration purposes, our messages is expected to be a array of int
*/
bool getMessage(std::array<int, 4>& message);
bool getIPAddress(std::array<int, 4>& message);
void setFoundIP();
bool isReady();
void nextPort();
int getPort();
private:
bool _isBoundToPort = false;
/**
* The server port.
*/
unsigned short port_;
bool isFoundIP = false;
/**
* The thread-safe message queue.
*/
Queue queue_;
Queue _ipAddresses;
/**
* The UDP server function.
*/
int UDPServerFunc();
};
cpp file:
#include "UDPServer.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/**
* This function parses an incoming message with the following format: 1;234;-89;-53;
*
* A valid message consists of 4 integer values separated by semicolons.
*/
inline std::array<int, 4> parseMessage(const std::string& input);
inline std::array<int,4> parseIp(const std::string& input);
UDPServer::UDPServer(unsigned short port) {
port_ = port;
}
bool UDPServer::getMessage(std::array<int, 4>& message) {
return queue_.pop(message);
}
bool UDPServer::getIPAddress(std::array<int, 4>& message) {
return _ipAddresses.pop(message);
}
void UDPServer::setFoundIP(){
isFoundIP = true;
}
bool UDPServer::isReady(){
return _isBoundToPort;
}
void UDPServer::nextPort(){
port_++;
}
int UDPServer::getPort(){
return port_;
}
void UDPServer::setupServer() {
// Launch the server thread.
std::thread t([this](){
UDPServerFunc();
});
t.detach();
}
int UDPServer::UDPServerFunc() {
// Creating socket file descriptor
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Filling server information
struct sockaddr_in servaddr, cliaddr;
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET; // IPv
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(port_);
// Bind the socket with the server address
if (::bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
_isBoundToPort = true;
while (true) {
// Read the next message from the socket.
char message[MAXBUFFER_SIZE];
socklen_t len = sizeof(struct sockaddr);
ssize_t n = recvfrom(sockfd, (char *)&message, MAXBUFFER_SIZE, MSG_DONTWAIT,
(struct sockaddr *)&cliaddr, (socklen_t*)&len);
if (n > 0) {
message[n] = '\0';
// Parse incoming data and push the result on the queue.
// Parsed messages are represented as a std::array<int, 4>.
if(!isFoundIP){
_ipAddresses.push(parseIp(message));
}else{
queue_.push(parseMessage(message));
}
} else {
// Wait a fraction of a millisecond for the next message.
usleep(100);
}
}
return 0;
}
I removed any unnecessary code from my answer, as the meat really is just the code above. If anyone needs the extraneous functions as well, I shared the code on Github, and will add some examples later on too.
The above code is really simple and has a couple of parse functions for extracting an IP address, or a set of four numbers delimited by semicolons. The above code is simple enough to modify yourself for your own custom messages.
Queue.h is just a simple thread safe queue.

Kernel (Android) to Userspace message multicast error: netlink_broadcast_filtered+0x24/0x3d4

I am trying to develop a function which would enable the Kernel (Android kernel: 4.9.59) to send a message to an/many userspace application and I have followed this example: Kernel to userspace application communication
However, when I am trying to call the message conveying function from the scheduler I am receiving the following error:
Fatal exception
PC is at netlink_broadcast_filtered+0x24/0x3d4
LR is at netlink_broadcast+0x14/0x20
Inside the kernel scheduler (kernel/sched) I have created a header (custom_code.h) which holds the function to send message from the kernel. I am not using Kernel module to inject this because Android does not support modules. The code inside custom_code.h is as follows:
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#define MY_GROUP 1 //For netlink socket
struct sock* socket; //For netlink socket
struct sk_buff* socket_buff; //For netlink socket
static inline void nl_receive_callback (struct sk_buff *skb)
{
nlmsg_free(skb);
}
struct netlink_kernel_cfg cfg = {
.input = nl_receive_callback,
.groups = 1,
};
static inline int kernel_send_nl_msg(void)
{
struct nlmsghdr *nlsk_mh;
char* msg = "hello from kernel";
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
socket_buff = nlmsg_new(256, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
//NETLINK_CB(socket_buff).pid = 0; // kernel pid pid is deprecated
NETLINK_CB(socket_buff).portid = 0;
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
pr_info("%s", msg);//Print out the message to kernel
return 0;
}
I am calling the kernel_send_nl_msg from the sugov_start(struct cpufreq_policy *policy) function inside the cpufreq_schedutil.c (kernel/sched/cpufreq_schedutil.c), and I have built the whole kernel and flashed it on an Android device.
My modified code inside the kernel/sched/cpufreq_schedutil.c as follows:
static int sugov_start(struct cpufreq_policy *policy)
{
struct sugov_policy *sg_policy = policy->governor_data;
unsigned int cpu;
sg_policy->up_rate_delay_ns =
sg_policy->tunables->up_rate_limit_us * NSEC_PER_USEC;
sg_policy->down_rate_delay_ns =
sg_policy->tunables->down_rate_limit_us * NSEC_PER_USEC;
update_min_rate_limit_us(sg_policy);
sg_policy->last_freq_update_time = 0;
sg_policy->next_freq = UINT_MAX;
sg_policy->work_in_progress = false;
sg_policy->need_freq_update = false;
sg_policy->cached_raw_freq = 0;
for_each_cpu(cpu, policy->cpus) {
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
memset(sg_cpu, 0, sizeof(*sg_cpu));
sg_cpu->sg_policy = sg_policy;
sg_cpu->flags = 0;
sugov_start_slack(cpu);
sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
policy_is_shared(policy) ?
sugov_update_shared :
sugov_update_single);
}
if(kernel_send_nl_msg() != 0)
pr_info("Error sending message from Kernel using socket");
return 0;
}
After flashing the kernel image to the device and trying to boot the aformentioned error is conveyed by the device (even without booting).
My question on the error is as follows:
1) What might be the issue that is causing the error?
2) How can I send messages successfully from Android kernel to an/many userspace application? Any suggestion would be really helpful.

Kernel to userspace application communication

I am trying to make Kernel (Android, kernel 4.9.59) communicate with userspace applications. I found a solution using Netlink sockets: https://stackoverflow.com/a/25071310/4190159
The first issue with the solution is that struct netlink_skb_parms used in the solution does not have a member named 'pid', instead has a member named 'portid', which I believe is not the same as pid. Anyway, to compile my kernel side code/solution I used 'portid' member of struct netlink_skb_parms instead for initialization. However, now I am getting a different error.
My Kernel side Netlink socket code as follows:
#include <linux/sched.h>
//For netlink socket -->
#include <net/sock.h>
//#include <net/netlink.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#define MY_GROUP 1 //For netlink socket
struct sock* socket; //For netlink socket
struct sk_buff* socket_buff; //For netlink socket
static void nl_receive_callback (struct sk_buff *skb)
{
nlmsg_free(skb);
}
static void kernel_send_nl_msg(void)
{
struct nlmsghdr *nlsk_mh;
char* msg = "hello from kernel";
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);
socket_buff = nlmsg_new(256, GFP_KERNEL);
nlsk_mh = nlmsg_put(socket_buff, 0, 0, NLMSG_DONE, strlen(msg), 0);
//NETLINK_CB(socket_buff).pid = 0; // kernel pid is deprecated
NETLINK_CB(socket_buff).portid = 0;
NETLINK_CB(socket_buff).dst_group = MY_GROUP;
strcpy(nlmsg_data(nlsk_mh), msg);
nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL);
pr_info("%s", msg);//Print out the message to kernel
return;
}
My userspace application side code to intercept the message from the kernel as follows:
#include <sys/socket.h>
#include <linux/netlink.h>
#define MY_GROUP 1
void user_recieve_nl_msg(void)
{
int sock_fd;
struct sockaddr_nl user_sockaddr;
struct nlmsghdr *nl_msghdr;
struct msghdr msghdr;
struct iovec iov;
char* kernel_msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
memset(&user_sockaddr, 0, sizeof(user_sockaddr));
user_sockaddr.nl_family = AF_NETLINK;
user_sockaddr.nl_pid = getpid();
user_sockaddr.nl_groups = MY_GROUP;
bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));
while (1) {
nl_msghdr = (struct nlmsghdr*) malloc(NLMSG_SPACE(256));
memset(nl_msghdr, 0, NLMSG_SPACE(256));
iov.iov_base = (void*) nl_msghdr;
iov.iov_len = NLMSG_SPACE(256);
msghdr.msg_name = (void*) &user_sockaddr;
msghdr.msg_namelen = sizeof(user_sockaddr);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
recvmsg(sock_fd, &msghdr, 0);
kernel_msg = (char*)NLMSG_DATA(nl_msghdr);
print("Kernel message: %s\n", kernel_msg); // print to android logs
}
close(sock_fd);
}
When I am trying to build the android kernel I am receiving the fllowing error:
kernel/sched/custom_code.h:34:65: error: passing argument 3 of
'netlink_kernel_create' makes pointer from integer without a cast
[-Werror]
kernel/sched/custom_code.h:34:14: error: too many arguments to
function 'netlink_kernel_create'
Note the code for the Kernel side is written in custom_code.h.
My questions are as follows:
I have checked the function 'netlink_kernel_create' and I am sending the right number of arguments then why is the aformentioned error coming up? How this error could be resolved?
What should I do to establish a valid communication between the kernel and the userspace application so that messages could be passed (to and fro) between them?
1.
Let's check netlink_kernel_create function in linux kernel:
static inline struct sock *
netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
{
return __netlink_kernel_create(net, unit, THIS_MODULE, cfg);
}
from here https://elixir.bootlin.com/linux/v4.9.59/source/include/linux/netlink.h#L60
Notice, that this function takes only 3 arguments ( instead of 6 in your code )
This function have been changed in kernel 3.6 ( from 6 parameters to 4 )
https://elixir.bootlin.com/linux/v3.6/source/include/linux/netlink.h#L185
And then renamed to __netlink_kernel_create in kernel 3.7
netlink_kernel_create function from 3.7 accepts 3 arguments
https://elixir.bootlin.com/linux/v3.7/source/include/linux/netlink.h#L48
Try change this
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 1, nl_receive_callback, NULL, THIS_MODULE);
to this
struct netlink_kernel_cfg cfg = {
.input = nl_receive_callback,
.groups = 1,
};
socket = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
Now you can send data in direction "kernel => application".
When you start your application, it will bind socket with user_sockaddr.nl_groups = MY_GROUP; bind(sock_fd, (struct sockaddr*)&user_sockaddr, sizeof(user_sockaddr));.
After this you can send data from kernel to application with NETLINK_CB(socket_buff).dst_group = MY_GROUP; nlmsg_multicast(socket, socket_buff, 0, MY_GROUP, GFP_KERNEL); and it will be received by application with recvmsg(sock_fd, &msghdr, 0);
How can I call kernel_send_nl_msg() function to actually communicate with the userspace?
You can call it from kernel module, which you write, compile and insmod into kernel. Or you can call it directly from kernel, but for this you will need to rebuild whole kernel.
If you want to send data in direction "application = > kernel", then you need to do things in reverse: bind new socket with another MY_GROUP2 in kernel and send data from application with nlmsg_multicast

Cannot connect to Bluetooth/BlueZ server: Could not create RFCOMM socket

I am trying to create a simple and custom Bluetooth connection between my Linux laptop and Android phone. On the Linux side of things, I use the BlueZ libbluetooth library to set up a server. The code for it is very similar to others I've seen floating around on github:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
sdp_session_t *register_service();
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
char str[1024] = { 0 };
int s, client, bytes_read;
sdp_session_t *session;
socklen_t opt = sizeof(rem_addr);
session = register_service();
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 11;
printf("Trying to bind...");
fflush(stdout);
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
printf("bound\n");
fflush(stdout);
printf("Waiting for connection...");
fflush(stdout);
listen(s, 1);
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
sprintf(str,"to Android.");
printf("sent [%s]\n",str);
write(client, str, sizeof(str));
close(client);
close(s);
sdp_close( session );
return 0;
}
sdp_session_t *register_service()
{
uint32_t svc_uuid_int[] = { 0x00000000,0x00000000,0x00000000,0x3233 };
uint8_t rfcomm_channel = 11;
const char *service_name = "Remote Host";
const char *service_dsc = "What the remote should be connecting to.";
const char *service_prov = "Your mother";
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
sdp_list_t *l2cap_list = 0,
*rfcomm_list = 0,
*root_list = 0,
*proto_list = 0,
*access_proto_list = 0;
sdp_data_t *channel = 0, *psm = 0;
sdp_record_t *record = sdp_record_alloc();
// set the general service ID
sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
sdp_set_service_id( record, svc_uuid );
sdp_list_t service_class = {NULL, &svc_uuid};
sdp_set_service_classes( record, &service_class);
// make the service record publicly browsable
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root_list = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups( record, root_list );
// set l2cap information
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append( 0, &l2cap_uuid );
proto_list = sdp_list_append( 0, l2cap_list );
// set rfcomm information
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
sdp_list_append( rfcomm_list, channel );
sdp_list_append( proto_list, rfcomm_list );
// attach protocol information to service record
access_proto_list = sdp_list_append( 0, proto_list );
sdp_set_access_protos( record, access_proto_list );
// set the name, provider, and description
sdp_set_info_attr(record, service_name, service_prov, service_dsc);
int err = 0;
sdp_session_t *session = 0;
// connect to the local SDP server, register the service record, and
// disconnect
session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
err = sdp_record_register(session, record, 0);
// cleanup
//sdp_data_free( channel );
sdp_list_free( l2cap_list, 0 );
sdp_list_free( rfcomm_list, 0 );
sdp_list_free( root_list, 0 );
sdp_list_free( access_proto_list, 0 );
return session;
}
I am able to run the server side code in Linux without error:
$ ./bluetooth-server
Trying to bind...bound
Waiting for connection...
I am then able to use sdptool to see my RFCOMM socket and service (description, channel number, and all other information look correct):
Service Name: Remote Host
Service Description: What the remote should be connecting to.
Service Provider: Your mother
Service RecHandle: 0x10009
Service Class ID List:
UUID 128: 00000000-0000-0000-0000-000033320000
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 11
Now, on the Android side of things I first pair the phone to the Linux server via the standard settings screen. Once paired, I then use code on the Android side of things to scan for Bluetooth devices, and if it is my Linux device then I try to connect to it. I have tried two different methods that people have suggested on stack overflow to make the connection:
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getName().equals("ubuntu-0")) {
try {
mBluetoothAdapter.cancelDiscovery();
// This returns the value 00001103-0000-1000-8000-00805f9b34fb
UUID uuid = device.getUuids()[0].getUuid();
// This does not work
//BluetoothSocket tmp = device.createRfcommSocketToServiceRecord(uuid);
// And neither does this
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
BluetoothSocket tmp = (BluetoothSocket) m.invoke(device, 11); // Match channel 11
tmp.connect(); // Exception is thrown here
}
catch(Exception e) {
Log.e("BT", "Could not create RFCOMM socket " + e.toString());
}
}
}
I keep getting the following Exception being thrown when I actually try the tmp.connect() call:
03-20 14:20:13.089: E/BT(16915): Could not create RFCOMM socket
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
Does anyone see what I am doing wrong here in trying to create the connection? Note that I do get a UUID returned when I call UUID uuid = device.getUuids()[0].getUuid(); ... this leads me to believe that the pairing is OK, which returns the value 00001103-0000-1000-8000-00805f9b34fb.
Maybe this could be reason if you pair your device before running ./bluetooth-server then rfcomm service record is not added and remote device will not information about this and if remote device does not do the service discovery then it will not be able to connect to your device.

Control a relay using an Android by Wi-Fi

How can I turn on or turn off a switch using Android and a Wi-Fi connection?
I have used SparkFuns IOIO to control relays. But how do I do it wirelessly?
I have a project just like this. Mine is sending position data for a steering system, but the idea is the same. I'll finish uploading it to Google Code soon. You can check it out at PowerWheelino.
The basic structure is this:
Touch event on Android sends data (over UDP) to the server.
The UDP server (WRT54G router in this case) receives the data and forwards it over serial to the Arduino.
The Arduino decides what to do with the data from the serial connection.
Keep in mind that the Arduino automatically resets when receiving data over serial (outside of the IDE Serial interface). See my post here on this topic and ways to get around it. Knowing this previously would have saved me a lot of troubleshooting.
Disclaimer:
This code requires some minor modification to accomplish what was requested by the OP. Since you've already made a working Android program with IOIO and an Arduino sketch, I assume this is within your abilities.
Here's the Android UDP client code:
Execute UdpClient::sendData() on touch event or button press.
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.util.Log;
public class UdpClient {
String messageStr;
DatagramSocket s;;
int server_port;
InetAddress local;
int msg_length;
byte[] message;
public UdpClient (String ipAddress, int port){
server_port = port;
try {
local = InetAddress.getByName(ipAddress);
s = new DatagramSocket();
}
catch (Exception e) {
e.printStackTrace();
Log.d("Powerwheelino",e.getStackTrace() + "error");
}
}
public boolean sendData(byte drive, byte steering){
byte drvByte = (byte) (drive & 0xFF);
byte steerByte = (byte) (steering & 0xFF);
message = new byte[2];
message[0] = drvByte;
message[1] = steerByte;
msg_length = message.length;
//message = messageStr.getBytes();
try {
DatagramPacket p = new DatagramPacket(message, msg_length,local,server_port);
s.send(p);
}
catch (Exception e) {
// TODO Auto-generated catch block
Log.d("Powerwheelino", e.getStackTrace() +"ERROR ");
e.printStackTrace();
return false;
}
return true;
}
}
Here's the listening UDP server (C++) code
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <SerialStream.h>
using namespace std;
class udp_server {
int sock;
int bytes_read;
socklen_t addr_len;
struct sockaddr_in server_addr , client_addr;
public:
udp_server(int portNum)
{
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock,(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
printf("\nUDPServer Waiting for client on port %d", portNum);
fflush(stdout);
}
int listen(char recv_data[]) {
while (1)
{
bytes_read = recvfrom(
sock,
recv_data,
1024,
0,
(struct sockaddr *)&client_addr,
&addr_len
);
recv_data[bytes_read] = '\0';
printf("\n(%s , %d) said : ",inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
printf("%s", recv_data);
string drive;
string direction;
int speed, angle;
if ((recv_data[0] & 128) > 0) {
drive = "Fwd";
}
else {
drive = "Rev";
}
if ((recv_data[1] & 128) > 0) {
direction = "Left";
}
else {
direction = "Right";
}
speed = recv_data[0] & 127;
angle = recv_data[1] & 127;
printf("\t %s # %d and %s # %d",
drive.c_str(),
speed,
direction.c_str(),
angle);
fflush(stdout);
}
return 0;
}
};
Here's a snippet of the serial communication to the Arduino using LibSerial:
LibSerial::SerialStream myss;
SerialComm(int argc, char** argv) {
myss = new LibSerial::SerialStream("/dev/ttyS0", ios_base::out);
myss.SetBaudRate(LibSerial::SerialStreamBuf::BAUD_57600);
myss.SetCharSize(LibSerial::SerialStreamBuf::CHAR_SIZE_8);
myss.SetFlowControl(LibSerial::SerialStreamBuf::FLOW_CONTROL_NONE);
myss.SetParity(LibSerial::SerialStreamBuf::PARITY_NONE);
myss.SetNumOfStopBits(1);
const int Dsize = 2;
char buffer[1];
buffer[0] = 125; //0b00000001;
buffer[1] = '\0';
bitset(buffer[0]);
//myss << buffer;
myss.write(buffer,1);
//myss.Close();
}
You could use an Arduino with an Ethernet Shield - or possibly a Netduino. Basically, any device with wireless internet capabilities, since that is the only wireless protocol Android uses - besides Bluetooth (or NFC). When the user presses a button, you could open a Socket or a BluetoothSocket to communicate to the second device that it needs to open the switch. Fairly simple - if you have a wireless home network, then your device could be plugged in to your router with a physical wire - as long as your Android device and your microprocessor are on the same network. There might be other wireless options you could use - these are just the simplest I could thing of. Hope this helps!
That's why how I did it with my iPhone (should be the same on Android):
run a TCP server on a computer connected to the same network as your phone and by USB/serial to the Arduino.
This server should forward all incoming data coming through Wi-Fi from your Android phone through USB to the Arduino.
The phone should run a TCP client which sends a simple one-byte (maybe zero and non-zero) command
The Arduino shall be programmed so it listens for incoming serial data via interrupts; if a byte arrives it decides if it should switch the I/O pin on or off.
You can also use a Rugged Circuits Yellowjacket. It has a Wifi on board and can serve simple web pages and control inputs/outputs.

Categories

Resources