I am actually develop an app (spectrum analyzer) on smartphone. This app can communicate by bluetooth with a raspberry pi 3 and scan frequency from my RTLSDR-2832 (plug on RPI3).
I wrote a script to get samples from my RTLSDR-2832 and I send it on my app by bluetooth :
from pylab import*
from rtlsdr import*
from bluetooth import*
import sys
#configure device
sdr= RtlSdr()
sdr.sample_rate=double(sys.argv[3])
sdr.gain=double(sys.argv[2])
sdr.center_freq=double(sys.argv[1])
NFFT=50
#Bluetooth connection
server_sock=BluetoothSocket(RFCOMM)
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port=server_sock.getsockname()[1]
uuid="94f39d29-7d6d-437d-973b-fba39e49d4ee"
client_sock,client_info=server_sock.accept()
while(1):
samples=sdr.read_samples(256*1024)
result=psd(samples,NFFT, Fs=sdr.sample_rate/1e6, Fc=sdr.center_freq*1e6/1e6)
tab_freq=(result[1]/1e6)
value_freq=str(tab_freq)[1:-1]
value_list=[format(float(v), ".10f") for v in value_freq.split()]
value_freq2= "\n".join(value_list)
tab_pxx=result[0]
value_pxx=str(tab_pxx)[1:-1]
client_sock.send(value_freq2+'\n'+'\n'.join(value_pxx.split()))
So with this script, I can get data from my RTLSDR2838 and send data. I send by bluetooth all data freq in first then, pxx value (in db/Hz).
I get all data on my app with that :
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
boolean running;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
running = true;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
#Override
public void run() {
byte[] buffer = new byte[1048576]; // 20 bits
int bytes;
String strRx = "";
while (running) {
try {
bytes = connectedInputStream.read(buffer);
final String strReceived_freq = new String(buffer,0, 15*nb_points);
final String strReceived_pxx = new String(buffer,15*nb_points, bytes);
//final int samples_sdr=new Integer(buffer,0,bytes);
final String strByteCnt = String.valueOf(bytes) + " bytes received.\n";
runOnUiThread(new Runnable(){
#Override
public void run() {
Pxx_value.setText(strReceived_pxx+"\n"); // get data PXX
freq_value.setText(strReceived_freq+"\n"); // get data freq
// plot value
/* for (int i=0; i<nb_points; i++)
{
freq[i]=Double.parseDouble(strReceived_freq);
pxx[i]=Double.parseDouble(strReceived_pxx);
series.appendData(new DataPoint(freq[i],pxx[i]), true,500);
}*/
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
cancel();
final String msgConnectionLost = "Connection lost:\n" + e.getMessage();
runOnUiThread(new Runnable(){
#Override
public void run() {
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
running = false;
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The variable nb_points is fix to 50 like NFFT on my script. But when I did that I don't get my 50 values. If I try to fix nb_points and NFFT at 30 or less it works but not after...
I thinked at early maybe the problem is from the buffer but no apparently...
Did someone have any idea to fix this ?
Thanks for your help !
EDIT : It works until 33 exactly, after I don't know if it's about my buffer or not, but for each case of my tab, I get 2 values in sames times (my frequence, and pxx value) as the tab is writing again
Related
I have to create a simple rotating proxy application where 100 requests get evenly distributed to 10 devices. I've got the following structure:
WebServer with a Java-SocketServer running. All Android devices are connected to this Socket-Server to be able to know which devices are currently online and for determining which device should be used for the next request.
10 Android devices in different networks. They are connected to the Socket Server and are waiting for requests that should be forwarded to the remote address and then sent back to the SocketServer.
In easy words: I basically have to create an application similar like Honeygain, Peer2Profit or IPRoyal Pawns so that I can later do requests like this:
//Use "-x" to set Proxy-IP and Proxy-Port
curl -x ANDROID_DEVICE_IP:PORT -L https://www.google.com
I managed to have an always running proxy service in an Android application. It basically looks like this and just forwards HTTP-Requests from Port 1440 to the desired remote address and then sends the response back to the original client. The Proxy basically works fine.
public class ProxyServerThread extends Thread {
public static void main(String[] args) {
(new ProxyServerThread()).run();
}
public ProxyServerThread() {
super("Server Thread");
}
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(1440)) {
Socket socket;
try {
while ((socket = serverSocket.accept()) != null) {
(new Handler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
return;
}
}
public static class Handler extends Thread {
public static final Pattern CONNECT_PATTERN = Pattern.compile("CONNECT (.+):(.+) HTTP/(1\\.[01])", Pattern.CASE_INSENSITIVE);
private final Socket clientSocket;
private boolean previousWasR = false;
public Handler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try {
String request = readLine(clientSocket);
System.out.println(request);
Matcher matcher = CONNECT_PATTERN.matcher(request);
if (matcher.matches()) {
String header;
do {
header = readLine(clientSocket);
} while (!"".equals(header));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(clientSocket.getOutputStream(), "ISO-8859-1");
final Socket forwardSocket;
try {
forwardSocket = new Socket(matcher.group(1), Integer.parseInt(matcher.group(2)));
System.out.println(forwardSocket);
} catch (IOException | NumberFormatException e) {
e.printStackTrace(); // TODO: implement catch
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 502 Bad Gateway\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
return;
}
try {
outputStreamWriter.write("HTTP/" + matcher.group(3) + " 200 Connection established\r\n");
outputStreamWriter.write("Proxy-agent: Simple/0.1\r\n");
outputStreamWriter.write("\r\n");
outputStreamWriter.flush();
Thread remoteToClient = new Thread() {
#Override
public void run() {
forwardData(forwardSocket, clientSocket);
}
};
remoteToClient.start();
try {
if (previousWasR) {
int read = clientSocket.getInputStream().read();
if (read != -1) {
if (read != '\n') {
forwardSocket.getOutputStream().write(read);
}
forwardData(clientSocket, forwardSocket);
} else {
if (!forwardSocket.isOutputShutdown()) {
forwardSocket.shutdownOutput();
}
if (!clientSocket.isInputShutdown()) {
clientSocket.shutdownInput();
}
}
} else {
forwardData(clientSocket, forwardSocket);
}
} finally {
try {
remoteToClient.join();
} catch (InterruptedException e) {
e.printStackTrace(); // TODO: implement catch
}
}
} finally {
forwardSocket.close();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
}
private static void forwardData(Socket inputSocket, Socket outputSocket) {
try {
InputStream inputStream = inputSocket.getInputStream();
try {
OutputStream outputStream = outputSocket.getOutputStream();
try {
byte[] buffer = new byte[4096];
int read;
do {
read = inputStream.read(buffer);
if (read > 0) {
outputStream.write(buffer, 0, read);
if (inputStream.available() < 1) {
outputStream.flush();
}
}
} while (read >= 0);
} finally {
if (!outputSocket.isOutputShutdown()) {
outputSocket.shutdownOutput();
}
}
} finally {
if (!inputSocket.isInputShutdown()) {
inputSocket.shutdownInput();
}
}
} catch (IOException e) {
e.printStackTrace(); // TODO: implement catch
}
}
private String readLine(Socket socket) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int next;
readerLoop:
while ((next = socket.getInputStream().read()) != -1) {
if (previousWasR && next == '\n') {
previousWasR = false;
continue;
}
previousWasR = false;
switch (next) {
case '\r':
previousWasR = true;
break readerLoop;
case '\n':
break readerLoop;
default:
byteArrayOutputStream.write(next);
break;
}
}
return byteArrayOutputStream.toString("ISO-8859-1");
}
}
}
Here comes the Problem:
Everything works fine but only on the local network. I cannot manage to get this to work without port forwarding. Since all devices are on their mobile cellular data I need a way to be able to connect to the device anyway.
How do the mentioned apps manage to connect to the devices?
My research showed (see pg. 5) that the maximum amount of data that can be sent via Bluetooth 4.2 is 257 bytes.
However, I was able to send 990 bytes between my Python script and Java application. Why was I able to send so much data? Is the information I found about the maximum data wrong, or did something else happen?
Python Bluetooth script:
#Parameters config
sdr=RtlSdr()
sdr.fc=100e6
sdr.gain=48
sdr.rs=1.024e6
#Bluetooth connection
server_sock=BluetoothSocket(RFCOMM)
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port=server_sock.getsockname()[1]
uuid="94f39d29-7d6d-437d-973b-fba39e49d4ee"
client_sock,client_info=server_sock.accept()
while (1):
samples= sdr.read_samples(256*1024)
result=psd(samples, NFFT=70, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6)
tab_freq=(result[1])
value_freq=str(tab_freq)[1:-1]
value_freq2=[format(float(v),".4f")[:6] for v in value_freq.split()]
value_freq3="\n".join(value_pxx2)
#SAME FOR POWER VALUE
#THEN I SEND DATA BY BLUETOOTH
client_sock.send(value_freq3)
Java Bluetooth code:
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
boolean running;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
running = true;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
#Override
public void run() {
byte[] buffer = new byte[1048576]; // 20 bits
int bytes;
String strRx = "";
while (running) {
try {
bytes = connectedInputStream.read(buffer);
final String strReceived_freq = new String(buffer,0, bytes/2);
final String strReceived_pxx = new String(buffer,(bytes/2)+1, bytes);
//final int samples_sdr=new Integer(buffer,0,bytes);
final String strByteCnt = String.valueOf(bytes) + " bytes received.\n";
runOnUiThread(new Runnable(){
#Override
public void run() {
Pxx_value.setText(strReceived_pxx+"\n"); // get data PXX
freq_value.setText(strReceived_freq+"\n"); // get data freq
// plot value
/* for (int i=0; i<nb_points; i++)
{
freq[i]=Double.parseDouble(strReceived_freq);
pxx[i]=Double.parseDouble(strReceived_pxx);
series.appendData(new DataPoint(freq[i],pxx[i]), true,500);
}*/
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
cancel();
final String msgConnectionLost = "Connection lost:\n" + e.getMessage();
runOnUiThread(new Runnable(){
#Override
public void run() {
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
running = false;
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The document you link to shows the LE (low energy) Link Layer packet format, as specified in Vol 6, Part B, Section 2.1 of the Bluetooth Core Specification.
You are using RFCOMM, which is a Bluetooth Classic (aka BR/EDR) profile. The Link Layer packet format for BR/EDR is specified in Vol 2, Part B, Section 6 and shows that the payload can be up to 2790 bytes long.
In any case the API you are using doesn't give you access to the Link Layer. You are writing on an RFCOMM channel (which is designed to work more or less like a serial port) and you can write as many bytes as you want. Your library and the underlying platform will take care of placing your data into the appropriate number of L2CAP packets, which will then be further encapsulated in link layer packets. The main limitation you will run into are the buffer sizes in your implementation. In this case your socket based API will return the number of bytes that were written in the call to send, and you will be able to attempt retransmission later.
Straight to the point - my application due to some mysterious reason looses part of a data (String) when receiving an InputStream. I am talking about Bluetooth connection here. Most of the time, I am receiving correct string but once in while it is shortened. Weirdest thing in here is that I am printing every InputStream into my ScrollView and I can tell that the whole string is there... Nevertheless here is the code:
#Override
public void run() {
InputStream inputStream;
try {
inputStream = mBTSocket.getInputStream();
while (!bStop) {
byte[] buffer = new byte[256];
int bytes;
if (inputStream.available() > 0) {
bytes = inputStream.read(buffer);
final String strInput = new String(buffer, 0, bytes);;
mTxtReceive.post(new Runnable() {
#Override
public void run() {
mTxtReceive.append(strInput);
int txtLength = mTxtReceive.getEditableText().length();
if (txtLength > mMaxChars) {
mTxtReceive.getEditableText().delete(0, txtLength - mMaxChars);
}
scrollView.post(new Runnable() {
#Override
public void run() {
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
weather = strInput.split(",");
mTxtHumidity.setText(weather[0]);
mTxtTemperatureDHT.setText(weather[1]);
mTxtPressure.setText(weather[2]);
mTxtLux.setText(weather[3]);
mTxtRainMM.setText(weather[4]);
mTxtRainDaily.setText(weather[5]);
mTxtWSKPH.setText(weather[6]);
mTxtWGKPH.setText(weather[7]);
mTxtWSAVG2.setText(weather[8]);
mTxtWGAVG10.setText(weather[9]);
}
});
}
Thread.sleep(500);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The problem in here is null exception on array weather as according to my app I am sometimes accessing items out of boundry (weather length is 6/7/8 most of the time once it errors). App crashes in 10% of the time.
Any reason behind it?
EDIT: while receiving InputStream sometimes instead of receiving 56 bytes I get 33 and 22 separetely
Answer to be found here: Android InputStream dropping first two bytes (modified BluetoothChat)
Adding
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
solves only for non-dynamic data exchange between Android and Arduino due to sleep method. It turns out that even sleep(50) works in this condition. For some reason after this short sleep buffer is never divided nor lost. If it is bad coding please explain before downvoting.
Hello dear programmers ,
I am trying to make a tic tac toe game using android, my android application contains several activities, one of these activities can the allows client to send a message to the server asking if X user wants to challenge, if the user accepts the challenge the server messages me and we both move forward to another activity.
My server is running as a regular java code on my PC, this is my server code :
public class Server {
ServerSocket serverSocket;
ArrayList<ServerThread> allClients = new ArrayList<ServerThread>();
public static void main(String[] args) {
new Server();
}
public Server() {
// ServerSocket is only opened once !!!
try {
serverSocket = new ServerSocket(6000);
System.out.println("Waiting on port 6000...");
boolean connected = true;
// this method will block until a client will call me
while (connected) {
Socket singleClient = serverSocket.accept();
// add to the list
ServerThread myThread = new ServerThread(singleClient);
allClients.add(myThread);
myThread.start();
}
// here we also close the main server socket
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class ServerThread extends Thread {
Socket threadSocket;
String userName;
boolean isClientConnected;
InputStream input;
ObjectInputStream ois;
OutputStream output;
ObjectOutputStream oos; // ObjectOutputStream
public ServerThread(Socket s) {
threadSocket = s;
}
public void sendText(String text) {
try {
oos.writeObject(text);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
try {
input = threadSocket.getInputStream();
ois = new ObjectInputStream(input);
output = threadSocket.getOutputStream();
oos = new ObjectOutputStream(output);
userName = (String) ois.readObject();
isClientConnected = true;
System.out.println("User " + userName + " has connected");
while (isClientConnected) {
String singleText = (String) ois.readObject();
System.out.println(singleText);
for (ServerThread t : allClients)
t.sendText(singleText);
// oos.writeObject(singleText);
}
// close all resources (streams and sockets)
ois.close();
oos.close();
threadSocket.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I use the communication between clients in only two activies, both activites contain the same connectUser() code :
public class MenuActivity extends Activity {
public static final String HOST = "10.0.2.2";
public static final int PORT = 6000;
static ConnectThread clientThread;
boolean isConnected;
static boolean isOnline = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
runOnUiThread(new Runnable() {
public void run() {
connectUser();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void connectUser() {
clientThread = new ConnectThread();
clientThread.start();
}
class ConnectThread extends Thread {
InputStream input;
OutputStream output;
ObjectOutputStream oos;
Socket s;
public void sendText(String text) {
try {
oos.writeObject(text);
System.out.println(text);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
try {
s = new Socket(HOST, PORT);
output = s.getOutputStream();
oos = new ObjectOutputStream(output);
oos.writeObject(un);
isOnline = true;
isConnected = true;
new ListenThread(s).start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ListenThread extends Thread {
Socket s;
InputStream input;
ObjectInputStream ois;
public ListenThread(Socket s) {
this.s = s;
try {
input = s.getInputStream();
ois = new ObjectInputStream(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
while (isConnected) {
try {
final String inputMessage = (String) ois.readObject();
//do something with the message }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
I use this code this code to send message to the server :
clientThread.sendText(user + " " + opponent + " play");
The problem is that when I create the connection at the first activity, then move to the second activity I create another connection , which means so far I am having two connections, same with other clients and then the server seems to return a timed out error.
My question is how to do a global client variable that is created once and can be used in each activity. I saw many suggestions like socket service or asyntask , but I need more direction and help
Thanks in advance.
Add a sub class of Application to your project and update application tag and add this class as android:name:
<application
android:name="com.your.app.MyApplication"
...
and then create a static reference to your Socket connection in MyApplication class:
private static Socket connection;
and then add a static method to access this object:
public static Socket getConnection() {
if( connection == null) {
// initialize connection object here
}
return connection;
}
Now you have a global object!
I am trying to send accelerator values over bluetooth from an Android App to the PC. I am working on the BluetoothChat demo application. In the Android App I have a method called onSensorChanged that will be called every time when the accelerations changes. the method looks like below:
#Override
public void onSensorChanged(SensorEvent e) {
// the work done when the accelerometer data changes
try {
Thread.sleep(25);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
sensorX = e.values[0];
sensorY = e.values[1];
Toast.makeText(BluetoothChat.this, "x coordinate = " + sensorX + "y coordinate = " + sensorY Toast.LENGTH_SHORT).show();
BigDecimal sensorXDec = new BigDecimal(e.values[0]).setScale(2,BigDecimal.ROUND_HALF_UP);
BigDecimal sensorYDec = new BigDecimal(e.values[1]).setScale(2,BigDecimal.ROUND_HALF_UP);
String vals = String.valueOf(sensorXDec.toPlainString() + "," + sensorYDec.toPlainString());
mChatService.writeFromString(vals);
}
The method writeFromString
public void writeFromString(String temp){
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.writeString(temp);
}
and the writeString method is the following:
public void writeString(String out) {
try {
if(D) Log.d(TAG, "Sending File....AS STRING");
mmOutStream.write(out.getBytes(), 0, out.getBytes().length);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
in the following method I process the inputStream on the PC side
#Override
public void run() {
try {
// prepare to receive data
InputStream inputStream = mConnection.openInputStream();
System.out.println("waiting for input");
while (true) {
int command = inputStream.read();
if (command == EXIT_CMD)
{
System.out.println("finish process");
break;
}
processCommand(command);
}
} catch (Exception e) {
e.printStackTrace();
}
}
The question again is: How can I retrieve each set of Strings I am sending from the Android App?
Try this
String msg = null;
BufferedReader br = new BufferedReader(
new InputStreamReader(inputStream)
);
msg = br.readLine();
This will solve problem
Scanner scanner = new Scanner (inputStream);
while(true){
if(!scanner.hasNextInt()){
continue;
}
// at this point we've got an int, so get it and use it
try{
int commmand = scanner.nextInt();
if (command == EXIT_CMD){
System.out.println("finish process");
break;
}
processCommand(command);
} catch (Exception catchThem){
// Deal with the caught exceptions
}
}
I didn't test this, hope it works for you.