I am trying to scan all visible wifi APs using wifimanger class. My question is that my code is working good when the (wifiscan-results) called repeatedly every 5 sec using recursive (Runnable) service. But when the time is reduced to be 1 sec or less, such that I register (wifimanger.statrscan) every 1 sec to receive the (wifiscan-results) every 1 sec, the output give null and gives values only every 4 second at least. Could you tell me why this happens. My aim to scan all visible wifi APs every one second or less, repeatedly, Is this possible?
Runnable function code:
public void Running() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
tv1.setText("counter : " + time1);
time1++;
Scan_number++;
mwifiManager.startScan();
periodic_recieving_wifi_signals();
Running();
}
}, 1000);}
broadcastreciever code:
public void periodic_recieving_wifi_signals() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION);
} else {
//flag1 = false;
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//tv2.setText("Each scan period is : " + results);
results = mwifiManager.getScanResults();
size = results.size();// number of the elements in the list
}
}, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}}
You almost certainly cannot get a WiFi scan every second ... the process simply takes too long.
I don't know all the technical details, and while some of the specific details may vary according to which version of WiFi you are using, looking at Wi-Fi / WLAN Channels, Frequencies, Bands & Bandwidths we can see that basic 2.4GHz 802.11 WiFi has 14 channels defined and 5GHz WiFi has 25 channels (not all channels are permitted in all locations).
To perform a scan, the radio in your phone has to tune to each channel in turn to see "what's out there". Seeing what (if anything) is on a particular channel will involve an exchange of messages, and will take a finite amount of time1 (it will have to wait "long enough" to tell the difference between a slow-to-respond device and "nothing there").
As you noted in a comment, if all of this is taking four seconds or so, you won't be able to perform a scan faster than about once every five seconds.
1 Thanks to John Hanley for supplying some numbers. By default, access points transmit their "I am here" beacons every 102.4ms. Thus some minimum scan-times are:
2.4GHz: 14 x 102.4ms = 1,433ms
5GHz: 25 x 102.4ms = 2,560ms
(Both figures may be slightly less in some locations, depending on the number or channels allowed to be used).
In practice, you would want to listen on each channel for longer than 102.4ms, otherwise you run the risk of not-quite-getting-a-beacon as you switch to a channel, and then switching from that channel just as (or before) the next beacon is sent. There may also be a small delay for the radio to stabilise to each new frequency.
This article: "SSID Overhead Calculator" from the Revolution WiFi website (as well as confirming the 102.4ms figure) also shows the dangers of having too many access-points (APs) and/or too many SSIDs... it doesn't take many of each before the time spent sending out these "beacon" frames takes a significant chunk out of your WiFi throughput. For example: 4 SSIDs on one AP (or 4 single-SSID APs on the same channel, or 2 double-SSID APs on the same channel) will each use about one-eighth of that channel's airtime just with "I am here" beacons!
Related
I am working with beacons in xamarin android. I want the scan to be done over 60 seconds and a period of 30 seconds to wait between the next cycle of scan.
public async void DetectAvailableBeacons()
{
_monitorNotifier = new MonitorNotifier();
_rangeNotifier = new RangeNotifier();
_tagRegion = new Region("Region",null, null, null);
_beaconManager.Bind(this);
_beaconManager.SetBackgroundScanPeriod(60000);
_beaconManager.SetForegroundScanPeriod(60000);
_beaconManager.SetBackgroundBetweenScanPeriod(30000);
_beaconManager.SetForegroundBetweenScanPeriod(30000);
_rangeNotifier.DidRangeBeaconsInRegionComplete += RangingBeaconsInRegionComplete;
}
The method RangingBeaconsInRegionComplete fills my list foundBeacons with the beacons detected.
Also, I have a method that gets all the available detected beacons as follows:
ObservableCollection<DetectedBeacon> BeaconLocator.GetAvailableBeacons()
{
return !_paused ? foundBeacons : null;
}
Now, I call the method GetAvailableBeacons() as follows:
public void PopulateBeacons() {
beaconsOnList = be.GetAvailableBeacons();
PopulateBeacons();
}
My issue is that sometimes it is missing some beacons, that is some beacons are not being detected. Also, the interval of scan does not seem to be working properly. Can someone advise what is wrong ?
In order for your scan periods to take effect right away, the easiest solution is to move the calls to set them before the call to bind so it looks like this:
_beaconManager.SetBackgroundScanPeriod(60000);
_beaconManager.SetForegroundScanPeriod(60000);
_beaconManager.SetBackgroundBetweenScanPeriod(30000);
_beaconManager.SetForegroundBetweenScanPeriod(30000);
_beaconManager.Bind(this);
By default, the scan will happen every 1.1 seconds and give you a result of all beacons seen in that period. This is probably what you are seeing happening without the code change above.
With shorter scan intervals, it is common for beacons with low advertising rates (e.g. ones that advertise only once every second) to not appear in the detection list for a single scan cycle. You can solve this by increasing the length of the scan cycle as you say you want to do, by increasing the advertising rate of the beacons, or building code logic that maintains a full list of beacons detected recently even if they weren't seen in the most recent scan cycle.
Short answer: If you increase your scan period successfully, I suspect this problem will go away.
I am looking for an android way to flush the characteristics the app receives from a Ble device, or at least know from the data that the connection has been lost as soon as it actually is except around 15 seconds after it disconnected. If there is a way to change the gatt connection timeout, that would be significantly better.
To repeat in a different form, I would like a solution (or a link that can explain) to detect a disconnect of the BLE device faster than whatever the timeout value currently is, by a means of seeing if the value I am getting is fresh by flushing the characteristic, or changing the disconnect timeout on the gatt side, so I can see within a second of it disconnecting to trigger other code.
Other answers in here may be better than this one, but this was my solution to the problem. Be sure to attempt Emil's answer before using this.
What I did since the time was too slow to wait for it was to check the rssi since it always is changing. If there is a period of time, lets say 3 seconds, where the value stays the same, it disconnects from the device. This goes around the 15 second timeout and adds our own timeout.
This would be what would be needed to check signal strength. This was written a couple of years ago, so some things may need to be changed.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status){
//check for signal strength changes. It will stay the same if we
//are getting no updates
if(mLastRssi == rssi){
disconnectCounter++;
if(disconnectCounter> 140) {
//disconnect logic as if we are done with connection
//maybe start listening for device again to reconnect
disconnectCounter = 0;
}
}
else{
//we are connected. reset counter
disconnectCounter = 0;
}
//store last value as global for comparison
mLastRssi= rssi;
}
}
Somewhere in a loop, call
mBluetoothGatt.readRemoteRssi()
Don't know if this would be of help, but you can take advantage (if you have it) of a periodic data that is transmitted in the gatt. So if for example you have a measurement of 1 second of periodicity you can do something like:
// runnable to detect the lack of activity:
private final Runnable watchDog = new Runnable() {
#Override
public void run() {
measurement_timeout--;
if(measurement_timeout==0) {
Log.d("BLE_CONTROLLER", "PROBE WITH NO ACTIVITY");
}
}
};
// this should be in the reception of the periodic data:
measurement_timeout++;
mHandler.postDelayed(watchDog, 3000);
So the "measurement_timeout" will work as an actual timeout that when it reaches the 0 means that you don't have data received in the period of 3000 ms.
Notice that you must have a watch time > 2*data period.
The only way I have managed to achieve a fast gatt disconnect has been to ensure that the peripheral device sends a BLE disconnect instruction before it powers down or severs the connection.
Once android receives the disconnect instruction, the gatt tidies up immediately instead of taking 15 seconds to realise the peripheral is missing.
It would seem that most peripherals do not bother and just disappear.
Clearly this approach is only possible if you are able to modify the peripheral.
The proper way is to use the Connection Parameter Update Request from the peripheral side to change the timeout to a lower value.
There is a callback in Android :
BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange( BluetoothGatt gatt,int status,int newState){
if(newState == BluetoothProfile.STATE_DISCONNECTED){
//your code here
}
}
}
Code in my current project periodically calls the WifiManager.startScan method and fetches the result via BroadcastReceiver:
void setupWifiScanner() {
final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
final IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(new BroadcastReceiver(){
public void onReceive(Context c, Intent i){
scanResultHandler(wifiManager.getScanResults());
wifiManager.startScan();
}
}, filter);
wifiManager.startScan();
}
The BroadcastReceiver gets called every 2-3 seconds when scanning 2,5Ghz and 5Ghz bands and every ~800ms when scanning the 2,5Ghz band only - this is fine. However, I'm facing an annoying problem. In a nutshell:
As long as there are APs in range, WifiManager.getScanResults returns up-to-date data
After leaving that range (e.g. leaving an urban area), the BroadcastReceiver still gets called, but from now on the getScanResults method will always return the last APs that were fetched - even if I am 20 miles away
As soon as there is at least one new AP in range, I suddenly get valid data again
In other words: getScanResults never returns an emtpy list (except perhabs for some seconds after the app was started). Either there are APs in range and the returned list is up-to-date, or there are no APs in range and the list is out-of-date (and contains the last seen APs).
I'm testing on a Nexus 5 with stock Android (4.4.4), but I'm quite sure the same code worked on a Galaxy Nexus six months ago.
I've got an idea regarding a workaround - just hashing the result and if the same hash occurs x-times in a row, I think it's safe to say that the data is not valid anymore (at least the signal strength of an AP should change between multiple scans). But maybe I'm doing something wrong and there is a simple solution. Any help is appreciated, thanks.
I developed a Data collector which collects data from Accelerometer, Gyroscope, Magnetometer and it worked fine for a while. Then I added Linear Acceleration to it as well (After 4 months, this week). Now both the version are behaving very strangely. Sometime they log the data perfectly when I do some physical activities like walking etc. However, sometimes it doesn't update sensors values and just repeat old values i.e each sensor value is updated lets after 5 seconds, 2 sec etc randomly and I need a sampling rate of 50 samples per second. I experimented with 10-15 participants and all my data was invalid because of this. The strange things is that the same app has worked perfectly before. I can't find any problem in it. I am placing some of the snapshots here. May be if someone can point to any bug or something ?
The buffered Writter:
FileWriter fow;
BufferedWriter bow;
extfile = new File(extfilepath, message + ".csv");
fow = new FileWriter(extfile);
bow = new BufferedWriter(fow);
This bow.writer is then being used in timertask thread to log data every 20 milliseconds.
Can anyone please comment or help me with this ? This weird behavior of this app is beyond my understanding.
Check that you have a wake lock acquired if your application goes to background. I've used PowerManager.PARTIAL_WAKE_LOCK successfully in a data collection application.
When your display turns off, your application is at least paused (and system might even stop it). The partial wake lock "Ensures that the CPU is running; the screen and keyboard backlight will be allowed to go off." So reading between the lines it means that otherwise your CPU might go to sleep for small periods of time in order to save power.
Did you forget to paste in:
else if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION){} ?
Are you using the accelerometer data, then subtracting gravity?
OK. What's your code look like to call the timer?? Something like this?
Timer updateTimer = new Timer("linear accel");
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 100);
}
private void updateGUI() {
runOnUiThread(new Runnable() {
public void run() {} } ?
I'm working on creating an app that allows very low bandwidth communication via high frequency sound waves. I've gotten to the point where I can create a frequency and do the fourier transform (with the help of Moonblink's open source code for Audalyzer).
But here's my problem: I'm unable to get the code to run with the correct timing. Let's say I want a piece of code to execute every 10ms, how would I go about doing this?
I've tried using a TimerTask, but there is a huge delay before the code actually executes, like up to 100ms.
I also tried this method simply by pinging the current time and executing only when that time has elapsed. But there is still a delay problem. Do you guys have any ideas?
Thread analysis = new Thread(new Runnable()
{
#Override
public void run()
{
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
long executeTime = System.currentTimeMillis();
manualAnalyzer.measureStart();
while (FFTransforming)
{
if(System.currentTimeMillis() >= executeTime)
{
//Reset the timer to execute again in 10ms
executeTime+=10;
//Perform Fourier Transform
manualAnalyzer.doUpdate(0);
//TODO: Analyze the results of the transform here...
}
}
manualAnalyzer.measureStop();
}
});
analysis.start();
I would recommend a very different approach: Do not try to run your code in real time.
Instead, rely on only the low-level audio code running in real time, by recording (or playing) continuously for a period of time encompassing the events of interest.
Your code then runs somewhat asynchronously to this, decoupled by the audio buffers. Your code's sense of time is determined not by the system clock as it executes, but rather by the defined inter-sample-interval of the audio data you work with. (ie, if you are using 48 Ksps then 10 mS later is 480 samples later)
You may need to modify your protocol governing interaction between the devices to widen the time window in which transmissions can be expected to occur. Ie, you can have precise timing with respect to the actual modulation and symbols within a "packet", but you should not expect nearly the same order of precision in determining when a packet is sent or received - you will have to "find" it amidst a longer recording containing noise.
Your thread/loop strategy is probably roughly as close as you're going to get. However, 10ms is not a lot of time, most Android devices are not super-powerful, and a Fourier transform is a lot of work to do. I find it unlikely that you'll be able to fit that much work in 10ms. I suspect you're going to have to increase that period.
i changed your code so that it takes the execution time of doUpdate into account. The use of System.nanoTime() should also increase accuracy.
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
long executeTime=0;
long nextTime = System.nanoTime();
manualAnalyzer.measureStart();
while (FFTransforming)
{
if(System.nanoTime() >= nextTime)
{
executeTime = System.nanoTime();
//Perform Fourier Transform
manualAnalyzer.doUpdate(0);
//TODO: Analyze the results of the transform here...
executeTime = System.nanoTime() - executeTime;
//guard against the case that doUpdate took longer than 10ms
final long i = executeTime/10000000;
//set the timer to execute again at the next full 10ms intervall
nextTime+= 10000000+ i*10000000
}
}
manualAnalyzer.measureStop();
}
What else could you do?
eliminate Garbage Collection
go native with the NDK (just an idea, this might as well give no benefit)