I have two iphone deveices connected by bluetooth. Is it possible to get signal strength between those deveices? if possible,How?
Thanks,
K.D
Take a look on Apple Sample Project for Transferring Data from One device to another via Bluetooth. BTLE Apple Sample Code
You can find out the signal strength with the value of RSSI (Received signal strength indication)
In sample code you will get RSSI value when data is received. Check the following method in BTLECentralViewController.m in Project:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
// Reject any where the value is above reasonable range
if (RSSI.integerValue > -15) {
return;
}
// Reject if the signal strength is too low to be close enough (Close is around -22dB)
if (RSSI.integerValue < -35) {
return;
}
NSLog(#"Discovered %# at %#", peripheral.name, RSSI);
// Ok, it's in range - have we already seen it?
if (self.discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it
self.discoveredPeripheral = peripheral;
// And connect
NSLog(#"Connecting to peripheral %#", peripheral);
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
Each time when u received data from advertising by another device. You will receive a RSSI value from this u can find strength and Range of device.
Also take a look on RSSI Details on Wiki
I hope this will helps u.
Related
I need to play sounds upon certain events, and want to minimize
processor load, because some image processing is being done too, and
processor performance is limited.
For the present, I play only one sound at a time, and I do it as
follows:
At program startup, sounds are read from .wav files
and the raw pcm data are loaded into memory
a sound device is opened (snd_pcm_open() in mode SND_PCM_NONBLOCK)
a worker thread is started which continously calls snd_pcm_writei()
as long as it is fed with data (data->remaining > 0).
Somewhat resumed, the worker thread function is
static void *Thread_Func (void *arg)
{
thrdata_t *data = (thrdata_t *)arg;
snd_pcm_sframes_t res;
while (1)
{ pthread_mutex_lock (&lock);
if (data->shall_stop)
{ data->shall_stop = false;
snd_pcm_drop (data->pcm_device);
snd_pcm_prepare (data->pcm_device);
data->remaining = 0;
}
if (data->remaining > 0)
{ res = snd_pcm_writei (data->pcm_device, data->bufptr, data->remaining);
if (res == -EAGAIN) continue;
if (res < 0) // error
{ fprintf (stderr, "snd_pcm_writeX() error: %s\n", snd_strerror(result));
snd_pcm_recover (data->sub_device, res);
}
else // another chunk has been handed over to sound hw
{ data->bufptr += res * bytes_per_frame;
data->remaining -= res;
}
if (data->remaining == 0) snd_pcm_prepare (data->pcm_device);
}
pthread_mutex_unlock (&lock);
usleep (sleep_us); // processor relief
}
} // Thread_Func
Ok, so this works well for one sound at a time. How do I play various?
I found dmix, but it seems a tool on user level, to mix streams coming
from separate programs.
Furthermore, I found the Simple Mixer Interface in the ALSA Project C
Library Interface, without any hint or example or tutorial about how
to use all these function described by one line of text each.
As a last resort I could calculate the mean value of all the buffers
to be played synchronously. So long I've been avoiding that, hoping
that an ALSA solution might use sound hardware resources, thus
relieving the main processor.
I'd be thankful for any hint about how to continue.
I'm using NSUbiquitousKeyValueStore to store some app settings. My logic is: when I save data locally, I save it to NSUbiquitousKeyValueStore also as a backup. When I need settings, I read locally and I only use iCloud key-value store if no data is found locally (after app is reinstalled, for example). If user has several devices sharing one icloud id, he can write settings on one device and download them to another (I warn him about rewrite).
I have a strange issue. Steps:
Installed an app and save its data to NSUbiquitousKeyValueStore. Made sure data is there.
Removed the app (assuming data is still persists in iCloud).
Waited several minutes just in case, then installed and launched the app from inside Xcode.
Tried to read a settings key using [[NSUbiquitousKeyValueStore defaultStore] dataForKey: #"mykeyname"] - sometimes it's ok, but sometimes key is not found!
Waited for 15 seconds, tried again. Success. Confused.
So it seems like ios needs some time to make remote key-value storage for my app available locally for dataForKey: call.
If I'd wrote such a system (actually I did - some time ago, in another life) there obviously must be a delay before asking and receiving a key-value data. So I'd like to have some notification saying: "we finished downloading/syncing key-value storage on first start" or something similar.
As far as I understand I can work with NSUbiquitousKeyValueStore in main thread synchronously (which is convenient for me). But [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] returns a valid url, and then I get "key isn't found". So I can't rely on it. Is there a way to be sure NSUbiquitousKeyValueStore works an is downloaded? It's important especially with slow internet.
UPDATE
Adding [[NSUbiquitousKeyValueStore defaultStore] synchronize] (as written in apple docs) to init and load was helped a little. Still there are many questions to iCloud.
Yesterday I've successfully saved data to the key-value store on phone 1 and restored on phone 2.
Today I've deleted app on phone 2 and tried to restore the data. But even [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] returned valid URL and I called [[NSUbiquitousKeyValueStore defaultStore] synchronize] I get nil when call dataForKey: MY_DATA_KEY.
When I tried to restore data from icloud on phone 1 (app is still installed) it succeeds, but when I reinstalled on this phone the app restore doesn't succeed any more.
Temporary solution is: "turn off iCloud->Documents&Data - turn off and on network - turn on Documents&Data", but also you should wait several minutes, and then it should work.
So, questions:
do you have such problems with iCloud?
Is there any way to find out is data not available or just not downloaded yet?
Is there any known "latency" of iCloud? I've heard about 7 seconds, but it's obviously not true.
It seems that when app isn't unistalled updates of iCloud data are pretty fast (seconds), but when you reinstall the app icloud needs several minutes to actualize key-value store. Is there any way to force this process?
P.S.
Below is my CloudHelper for your reference - pretty simple c++ class to write/read binary data to/from iCloud key-value store. It is not compilable, I've adapted it for SO somewhat to make more clear - removed my engine related code. Still if you remove MySystem::... calls it works pretty well. Except that I mentioned before.
class CloudHelper
{
public:
static bool init();
static void deInit();
//save our data to iCloud with
static int saveData(unsigned char* data, int from, int count);
//get our data from iCloud
static unsigned char * loadData(int *retsize, int * retint);
//does iCloud work for us
static bool isEnabled();
//do we have our key in iCloud
static int isAvailable();
static const int RESULT_OK = 0;
static const int RESULT_NO_CONNECTION = 1;
static const int RESULT_NOT_FOUND = 2;
static const int RESULT_SYNC_ERROR = 3;
private:
static bool enabled;
static NSURL *ubiq;
};
bool CloudHelper::enabled = false;
NSURL *CloudHelper::ubiq = NULL;
#define MY_DATA_KEY #"my_data_key"
int CloudHelper::saveData(unsigned char* data, int from, int count)
{
if ([NSUbiquitousKeyValueStore defaultStore])
{
NSData *d = [[[NSData alloc] initWithBytes:(data + from) length:count] autorelease];
[[NSUbiquitousKeyValueStore defaultStore] setData:d forKey: MY_DATA_KEY)];
if ([[NSUbiquitousKeyValueStore defaultStore] synchronize] != TRUE)
return RESULT_SYNC_ERROR;
return RESULT_OK;
}
return RESULT_NO_CONNECTION;
}
unsigned char * CloudHelper::loadData(int *retsize, int * retint)
{
if ([NSUbiquitousKeyValueStore defaultStore])
{
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
NSData *d = [[NSUbiquitousKeyValueStore defaultStore] dataForKey: MY_DATA_KEY];
if (d != NULL)
{
if (retsize != NULL)
*retsize = d.length;
if (retint != NULL)
*retint = RESULT_OK;
return d.bytes;
}
else
{
if (retsize != NULL)
*retsize = -1;
if (retint != NULL)
*retint = RESULT_NOT_FOUND;
}
}
else
{
if (retsize != NULL)
*retsize = -1;
if (retint != NULL)
*retint = RESULT_NO_CONNECTION;
}
return NULL;
}
int CloudHelper::isAvailable()
{
int result = RESULT_NO_CONNECTION;
if ([NSUbiquitousKeyValueStore defaultStore])
{
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
NSData *d = [[NSUbiquitousKeyValueStore defaultStore] dataForKey: MY_DATA_KEY];
if (d != NULL)
result = RESULT_OK;
else
result = RESULT_NOT_FOUND;
}
else
result = RESULT_NO_CONNECTION;
return result;
}
void CloudHelper::deInit()
{
enabled = false;
[ubiq release];
}
bool CloudHelper::init()
{
enabled = false;
NSURL *ubiq_ = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
if (ubiq)
{
enabled = true;
ubiq = [ubiq_ retain]; //save for further use
}
else
{
//is implemented elsewhere: this writes a local file with a counter, and if it is < REMINDER_COUNT allows us to show a warning to users
bool allow = MySystem::isAllowToShowDialog();
if (allow)
{
//determines network state with Apple's Reachability
if (!MySystem::isNetworkAvailable())
MySystem::showMessageBox(#"Network error"); //No network
else
MySystem::showMessageBox(#"You should log into your iCloud account to be able to backup your settings."); //No login
}
}
return enabled;
}
UPDATE 2
It's 2016. Android has become ios's evil twin, the humanity has discovered gravitational waves, Higgs have received his nobel, Microsoft has bought and killed Nokia. But iCloud is still as stupid as it was.
Finally I've made my own stack of network services on several VPS. I refused to use third-party services, because most of them are unstable and unpredictable. And yet I need iCloud. Because another die-born child of apple does not work. SecKeyChain. Its service dies when my game starts. So I decided to store random UUID in cloud to distinguish users (there is no device id anymore) even after reinstall. But what could go wrong? Everything! I've spend two days to make this stupid s*it to deploy without errors, and now it loses my data from time to time!
Thank you Apple, thank, thank, thank! La-la-la! Hip-hip hooray! (sounds of circus music, fading into weeping)
Conclusion
Temporary solution is:
- call synchronize before get data from key-value store
- to be sure it would work "turn off iCloud->Documents&Data - turn off and again on network - turn on Documents&Data", but also you should wait several minutes before iCloud downloads all needed data
Note: when app is installed and already worked (saved/loaded) with key-value store updates of iCloud data are pretty fast (7-15 sec), but when you reinstall the app it seems that icloud needs several minutes to actualize key-value store.
I'd be glad to hear your thoughts, because icloud looks like almost unusable feature. But I don't want to set up my own server to merely get the same functionality.
I am setting one dummy key to NSUbiquitousKeyValueStore and calling synchronize on app launch. The result is not 100% solution but somewhat better. You can try this.
Because obviously your app shouldn't hang while waiting for a slow netork. It's all in the iCloud Design Guide.
Register for NSUbiquitousKeyValueStoreDidChangeExternallyNotification, call -synchronize, and hopefully a notification should eventually arrive.
If the data is already up-to-date, I don't think you get a notification, and I don't think there's an wasy way to know how old the data is.
I am downloading file with ftp protocol. Now, to check the ability of dealing with error, I am simulating happening of some network error. The code to handle the network inputStream is as below:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
// An NSStream delegate callback that's called when events happen on our
// network stream.
{
#pragma unused(aStream)
assert(aStream == self.networkStream);
switch (eventCode) {
case NSStreamEventOpenCompleted: {
self.connected = YES;
} break;
case NSStreamEventHasBytesAvailable: {
NSInteger bytesRead;
uint8_t buffer[32768];
// Pull some data off the network.
bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];
DLog(#"%#,byteRead:%d",self.urlInput,bytesRead);
if (bytesRead == -1) {
[self _stopReceiveWithStatus:#"Network read error"];
} else if (bytesRead == 0) {
[self _stopReceiveWithStatus:#"success"];
} else {
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&buffer[bytesWrittenSoFar] maxLength:bytesRead - bytesWrittenSoFar];
DLog(#"%#,bytesWritten:%d",self.urlInput,bytesWritten);
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self _stopReceiveWithStatus:#"File write error"];
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != bytesRead);
}
} break;
case NSStreamEventHasSpaceAvailable: {
assert(NO); // should never happen for the output stream
} break;
case NSStreamEventErrorOccurred: {
[self _stopReceiveWithStatus:#"Stream open error"];
} break;
case NSStreamEventEndEncountered: {
assert(NO);
} break;
default: {
assert(NO);
} break;
}
}
If I turn off the wifi manually or turn off my wireless router (Network connection flag is off), a "NSStreamEventErrorOccurred" will be return and the downloading process will be terminated correctly. However, if I turn off the Modem, while keeping the wireless router open (Network connection flag is on). The downloading process stuck at the case "NSStreamEventHasBytesAvailable". Even after I turn on the internet connection , it is still stuck.
I want to know why it is stuck and how can I detect this kind of error. How can I deal with this situation?
First, kudos for considering this and running tests. Many developers assume that "the network connection will always work."
Second, it seems a little odd that you are using NSStream for FTP downloads; you do know that NSURLConnection supports FTP, right? Unless you are doing something really strange you should probably use the built-in URL loading facilities.
In any case, the issue here is that there is in principle no way for an application (or computer) to determine whether there has been a pause in a connection because the connection failed (and should be restarted or canceled) or because it simply is running slowly (in which case patience is required).
I'm a little surprised that an active TCP session is not resumed when your modem is reconnected; that suggests that maybe your ISP's router is dropping the connection when the modem link goes down or that your IP is changing on reconnection, but this isn't important for your question anyway.
TCP sessions will ordinarily eventually get timed out by the OS (or an upstream router) after a period of inactivity, but this might be an unacceptably long time. So the thing you probably need to do is implement a timeout.
What I'd probably do (assuming you stay the course with NSStream as discussed above) is have an NSTimer firing off periodically - maybe every 15 seconds - and have the callback compare the current time to a timestamp that you set on each NSStreamEventHasBytesAvailable event. If the timestamp is too old (say, more than 15 seconds), cancel or restart the download as desired and notify the user.
But again, take a look at just using NSURLConnection.
Is it possible to connect iMac to iPhone through the dock connector ? Also I am using the EAAccessory framework but I am not get any notifications when I connect the serial cable to iPhone. If any one knows about this please give me a suggestion.
There seems to be a lot of confusion regarding EAAccessoryManager and the accompanying classes. These are only for use with MFI sanctioned hardware i.e. those manufacturers that have taken the time to follow the MFI program and integrate the requisite hardware into their device.
The use of a chip and the establishment of a protocol allows for the facilitation of a communication stream between the app and the device.
Sam is correct in his statement but there is no need to jailbreak your app in order to bypass the MFI program however, you will not be able to submit to the App Store if you follow the procedure I am about to briefly outine:
Obtain all of the header files for the IOKit iOS OpenSource Browser
Add them to your solution
Include the IOKit.h framework
Head to http://www.arduino.cc/playground/Interfacing/Cocoa#IOKit for an example of how to use IOKit and icotl commands to achieve what you require
I have successfully implemented IOKit operations on an iOS device so this is definitely possible as long as you are willing to forego submission to the App Store.
Raj..
for get notification for connection accessory first of you have to register your accessory to MFI. otherwise you have to jailbreak your iPhone. for jail break check this code
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
static struct termios gOriginalTTYAttrs;
static int OpenSerialPort()
{
int fileDescriptor = -1;
int handshake;
struct termios options;
// Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
// The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
// See open(2) ("man 2 open") for details.
fileDescriptor = open("/dev/tty.iap", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fileDescriptor == -1)
{
printf("Error opening serial port %s - %s(%d).\n",
"/dev/tty.iap", strerror(errno), errno);
goto error;
}
// Note that open() follows POSIX semantics: multiple open() calls to the same file will succeed
// unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned
// processes.
// See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details.
if (ioctl(fileDescriptor, TIOCEXCL) == -1)
{
printf("Error setting TIOCEXCL on %s - %s(%d).\n",
"/dev/tty.iap", strerror(errno), errno);
goto error;
}
// Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block.
// See fcntl(2) ("man 2 fcntl") for details.
if (fcntl(fileDescriptor, F_SETFL, 0) == -1)
{
printf("Error clearing O_NONBLOCK %s - %s(%d).\n",
"/dev/tty.iap", strerror(errno), errno);
goto error;
}
// Get the current options and save them so we can restore the default settings later.
if (tcgetattr(fileDescriptor, &gOriginalTTYAttrs) == -1)
{
printf("Error getting tty attributes %s - %s(%d).\n",
"/dev/tty.iap", strerror(errno), errno);
goto error;
}
// The serial port attributes such as timeouts and baud rate are set by modifying the termios
// structure and then calling tcsetattr() to cause the changes to take effect. Note that the
// changes will not become effective without the tcsetattr() call.
// See tcsetattr(4) ("man 4 tcsetattr") for details.
options = gOriginalTTYAttrs;
// Print the current input and output baud rates.
// See tcsetattr(4) ("man 4 tcsetattr") for details.
printf("Current input baud rate is %d\n", (int) cfgetispeed(&options));
printf("Current output baud rate is %d\n", (int) cfgetospeed(&options));
// Set raw input (non-canonical) mode, with reads blocking until either a single character
// has been received or a one second timeout expires.
// See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") for details.
cfmakeraw(&options);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 10;
// The baud rate, word length, and handshake options can be set as follows:
cfsetspeed(&options, B19200); // Set 19200 baud
options.c_cflag |= (CS8); // RTS flow control of input
printf("Input baud rate changed to %d\n", (int) cfgetispeed(&options));
printf("Output baud rate changed to %d\n", (int) cfgetospeed(&options));
// Cause the new options to take effect immediately.
if (tcsetattr(fileDescriptor, TCSANOW, &options) == -1)
{
printf("Error setting tty attributes %s - %s(%d).\n",
"/dev/tty.iap", strerror(errno), errno);
goto error;
}
// Success
return fileDescriptor;
// Failure "/dev/tty.iap"
error:
if (fileDescriptor != -1)
{
close(fileDescriptor);
}
return -1;
}
int main(int args, char *argv[])
{
int fd;
char somechar[8];
fd=OpenSerialPort(); // Open tty.iap with no hardware control, 8 bit, BLOCKING and at 19200 baud
if(fd>-1)
{
write(fd,"*",1); // Write handshaking message over serial
///////////////////////////////////////////////////////////////////////////////////////////////////
// After this, our device or our PC program should be strobing serial ground to gain access to the Iphone Serial Line
//////////////////////////////////////////////////////////////////////////////////////////////////
read(fd,&somechar[0],1); // Read 1 byte over serial. This will block (wait) untill the byte has been received
if(somechar[0]=='*') // Check if this byte is a "handshaking" message
{
printf("Serial connection established!\n"); // If it is, we have established a connection to the device and can freely read/write over serial!
while(1) // Do this forever or untill someone presses CTRL+C
{
read(fd,&somechar[0],1); // Read a character over serial!
putchar(somechar[0]); // Write the character to the Terminal!!
}
}
}
return 0;
}
If you connect your iPhone to an iMac and you have either iTunes or Xcode running, you would be able to see that the iPhone is connected.
In Xcode, go to the Organizer window. In iTunes, look under the Devices in the left-hand column.
The EAAccessory framework, which I have not used, should have nothing to do with this.
Here is the answer: Launch specific app when external accessory attached - not all accessories can signal to launch app when they are connected. I think that ordinal USB cable also can't.
About IOKit: You can add nesessary files from Xcode itself - open Xcode.app package. IOKit framework is located in Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks
simply copy absent files (or make link) to
Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/IOKit.framework
and to
Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/System/Library/Frameworks/IOKit.framework
and also for all simulator platforms
You should know that not all functions of IOKit can work on real device (but they work under simulator) due to iOS sandbox security.
But You can work with IORegistry well. My first project on iOS was implemetation of the IORegistryExplorer.
Good luck!
I'm developing for the iPhone and am trying to get an initial timeStamp to sync my audioQueues.
I'm using AudioQueueDeviceGetCurrentTime for this. According to the documentation this function gives back a valid mHostTime whether the queue/device is running or not. But when I try this I get back a kAudioHardwareNotRunningError (1937010544). All queues have an timeLine associated and have been initialized before I call the function.
How can I retrieve a valid mHostTime to sync my AudioQueues (prior to running the queues)?
My code:
AudioSessionInitialize(NULL, NULL, interruptionListenerCallback, self);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(sessionCategory), &sessionCategory);
// initialize all queues
// ....
AudioSessionSetActive(true);
OSStatus result;
AudioTimestamp currentTime;
result = AudioQueueDeviceGetCurrentTime(audioQueueRef, ¤tTimeStamp);
if (!result)
{
// rest of code
}
After some googling I found a post on the CoreAudio mailing list where they say that the hostTime is the same as mach_absolute_time().
Mach_absolute_time() is indeed giving me expected timestamp values.
I spent about a week stuck with this exact problem. As far as I can tell, the documentation is wrong - you must have a running audio queue to query the current device time.
My solution? It's really inelegant, but I just keep one audio queue running at all times playing silence so that I can time other queues off it.
Try this, the function AudioQueueGetCurrentTime() fills an AudioTimeStamp structure. If you get the mSampleTime property of this structure and divide by audio sample rate you will obtain the current seconds position. In code:
// AudioTimeStamp struct to store the value.
AudioTimeStamp timeStamp;
// Gets the current audio queue time.
AudioQueueGetCurrentTime(
mQueue, // The audio queue whose current time you want to get.
NULL,
&timeStamp, // On output, the current audio queue time.
NULL
);
// Return the value.
NSTimeInterval seconds = timeStamp.mSampleTime / mRecordFormat.mSampleRate;
If you doesn't known the current sample rate, this information is stored on the mSampleRate property if you are using the CAStreamBasicDescription structure to control this.
Hope it works.
you have to create a timeline before you can call AudioQueueDeviceGetCurrentTime
AudioSessionSetActive(true);
// initialize all queues
// ....
// initialize time line
AudioQueueTimelineRef audioTimeline;
status = AudioQueueCreateTimeline(audioQueueRef, &audioTimeline);
// now you can do what you want.
OSStatus result;
AudioTimestamp currentTime;
result = AudioQueueDeviceGetCurrentTime(audioQueueRef, ¤tTimeStamp);
if (!result)
{
// rest of code
}