Knowing that data from an NSStream is complete - ios

I'am sending chunks of UIImage data over MCSession with an NSStream.
When I get bytes
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
if (eventCode == NSStreamEventHasBytesAvailable) {
// read data and append to self.data
// how to know that self.data can be used to create UIImage
}
}
I append them to a mutable data instance. The problem is how to know that the accumulated data represents a full image, so I can use -[UIImage initWithData:] to create it?

You should watch for NSStreamEventEndEncountered

The stream has no knowledge of its contents. If you can't rely on the stream ending to tell you that the data is complete, then you either need to use/create some protocol for the transmission that includes a "finished" signal, or just try to create the image and take appropriate action if that fails.

Related

ESP32 hardware ISR sometimes not triggered when wifi is transmitting

I tried to use hardware timer to read data from an external device periodically.
More specifically, I realized a custom driver using gpio to simulate SPI protocol, whenever an hardtimer interrupt happens, the driver is called to read gpio status. The timer is set to 2k.
When an interrupt happens, the isr shall put sample data into a buffer. When the buffer is full, the application will pause the timer and send these data out through mqtt protocol. Using signal generator and oscilloscope, I found the data was good. The whole process worked as expected.
The problem is that the sample process is not continual. When data is sending out through wifi, the timer is paused, and no data can be read into buffer.
To solve this problem, I create a special task responsible for transmitting data out. And then I use ping-pong buffers to store sample data. When one buffer is full, the sending task is notified to send these data out, meanwhile the timer isr is continually to put data into another buffer.
At first I wanted to send notify just from the isr (using xQueueSendFromISR()), which was proved not reliable. I found only a few notifies were able to be sent to the sending task. So I am obliged to using a flag. When one buffer is full, the flag is set to true, While a special task is looping this flag, whenever it find the flag is true, it will notify the sending task.
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)//it will cost 200ms to fill up the buffer
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
transmitting data out using mqtt protocol.
}
}
}
Then I got the terrible data as below.
terroble data
I used oscilloscope to check the gpio operation in the isr.
oscilloscope1
oscilloscope2
So it seems like some isr not triggered? but what happened?
More weird thing: I added another task to get data from an audio chip through i2s. Again I used ping-pong buffers and send notify to the same sending task.
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)
}
}
task_3()
{
while(1)
{
i2s_read_to_buffer;
xQueueSend;
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
do something;
transmitting data out using mqtt protocol
}
}
}
}
And this time the data from former task turned ok!
data_ok
And what's more, after I commened task2-related code in the sending task, Again the data become bad!
So what happened? Can somebody give any hint?
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
// do something;
// transmitting data out using mqtt protocol
}
}
}
}
I have solved this problem.
If you enable power management(idf.py menuconfig-->component config-->power management), the APB(advanced peripheral bus) will low its frequency automatically, which is the clock source of hardware timer.Thus you will see the timer interrupt is not stable.
Just disable the power management.

Download Firebase Storage Synchronously

I am working on downloading an image from Firebase Storage and displaying it on a table view. I have been using this:
referenceOfImage.data(withMaxSize: 100 * 1024 * 1024) { data, error in
if let error = error {
print(error)
} else {
guard let data = data else {
print("no data")
return
}
guard let image = UIImage(data: data) else {
print("no image")
return
}
//use image
}
}
However, according to documentation, the task
Asynchronously downloads the object at the FIRStorageReference to an NSData object in memory.
I am currently using a loop to download multiple images and it would work better if I could synchronously download the images (otherwise loop would continue and the task would be incomplete). How can I download the image synchronously? Thanks!
You can not. These methods are asynchronous because they require server calls, and making them synchronous would block the main thread and cause very poor UX and performance. You could set up your completion call to do a bit of recursion, perhaps?
Stick the image load into a function that takes an array of things to fetch, the current index, and a selector to call when finished. Have a terminating condition (index == array.count), which calls the selector you want to happen when all images are loaded, otherwise fetch the image at the index, and in the completion handler, increment the index and fetch the next image by calling the same method.

Avoid using flags to control invocation of code

I am new to ReactiveCocoa and trying to understand , how I can model the following example using reactive cocoa commands: I am trying to read bytes from stream and this is done in the function "readStream". I want to prevent further calls to readStream , until I am done with the first batch of reading. As shown, I am using the "reading" flag, which is set when reading starts and is reset when reading is done. I would like to avoid using the flag "reading", can this be coded in a better way using reactive cocoa.
- (void) stream:(NSStream *) aStream handleEvent:(NSStreamEvent)eventCode {
..
case NSStreamEventHasBytesAvailable:
if (!self.reading){
self.reading = YES; //
[self readStream]; // Reads bytes from the stream
}
break;
- (void) readStream {
// Read data
self.reading = NO;
}
RACCommands enables button until the returned signal complete, I'm not sure the context with your code, if it locates in lower level global singleton component, you still need keep the flag.

Core-Bluetooth get wrong characters back as answers?

i need to develop an app wich can communticate with a peripheral and i use a BlueGigaModul. Basically i send commands and wait for the answere. Ive the problem that the response is not correct. The wrong character appears randomly. I send each second a command to my device. To bluetooth module get the correct data but the data i get on the iphone contains wrong characters? The data i get is bigger than 20 bytes but the module should split it.
1.
How could this be? Is it because i memcopy to early?
The method didUpdateValueForCharacteristic is called if the whole data arrived?
2.
Is it better to writeValue or updateCharacteristic?
3.
I only find one characteristic? Do i need one to send and one to receive?
Or do i need to unsubscribe after writeValue and resubscribe for receive data?
4.
Does CoreBluetooth check if the data is corrupt??
this is how i writeValue:
NSString * test = #"\r";
NSData *data = [test dataUsingEncoding:NSASCIIStringEncoding];
if(hr_characteristic != nil){
[_discoveredPeripheral writeValue:data forCharacteristic: hr_characteristic type:CBCharacteristicWriteWithResponse];
I check the response with:
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if(error != nil)
return;
int len=characteristic.value.length;
if(len != 0)
{
memcpy(pbuffer,[characteristic.value bytes],len);
pbuffer += len;
}
}
Atm i fill the buffer with all the data i receive. I send 10 times. After i received all compare the buffer with my expected answer.
I send 600 commands and have 34 wrong characters in it. The buffer is filled with 5230bytes.
Thanks

Starting multiple tasks based on an event in iOS

I am developing a bluetooth app using the EADemo example. Whenever there is data in the bluetooth inputStream, the following event is invoked:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case 1:
//here I want to start two tasks
break;
}
And I have a common queue to which I have to write and read parallely.
The queue is actually a NSMutuableArray. In the write part, I use addobject:
and in the read part, I use objectAtIndex:0.
Any one has any idea how to move about this?
As you are using same array you will need to make it safe to access otherwise it may crash app
APPROACH A: (Using Grand Central Dispatch)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);//set priority as per requirement
//Read
dispatch_async(queue, ^{
while (//condition to stop)
{
//Perform read operation
}
});
//Write
dispatch_async(queue, ^{
while (//condition to stop)
{
//Perform write operation
}
});
//As operations are performed on same queue your array is safely accessed
APPROACH B: (Using threads)
Create two thread
Read Thread
Write tread
But access your array in synchronised manner.

Resources