Question

From my Arduino, I'm writing multi-byte data to serial with Serial.print("blah"), but in Objective-C, -serialPort:didReceiveData: (provided by ORSSerialPort) only gets this data 1 byte at a time. Occasionally, it'll grab 2 bytes at once, but never all 4. Is this expected? If so, how can I make it receive all 4 bytes at once?

Arduino:

void loop() {
    Serial.print("blah");
    delay(1000);
}

Obj-C:

- (void)serialPort:(ORSSerialPort *)serialPort didReceiveData:(NSData *)data {
   NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
   NSLog(@"%@",string);
}

Setting a breakpoint inside this method shows that data only holds 1 byte.

Was it helpful?

Solution

This is normal, expected behavior. The underlying serial hardware and software has no way of knowing how many bytes you're waiting for, or what a complete packet looks like, so it simply delivers data as it comes in. You'll have to buffer the data in your Objective-C code. Fundamentally, this is pretty simple. Create an NSMutableData that you can use as a buffer:

@property (strong) NSMutableData *incomingDataBuffer;

Initialize it (e.g. in -init):

_incomingDataBuffer = [[NSMutableData alloc] init];

Then, in your -serialPort:didReceiveData::

- (void)serialPort:(ORSSerialPort *)serialPort didReceiveData:(NSData *)data
{
   [self.incomingDataBuffer appendData:data];

   if ([self dataBufferHasCompletePacket]) { // Check to see if buffer contains a complete, valid packet
       [self processReceivedDataPacket:self.incomingDataBuffer]; // Do whatever you need to do with the received data
       [self.incomingDataBuffer replaceBytesInRange:NSMakeRange(0, [self.incomingDataBuffer length]) withBytes:NULL length:0]; // Clear data buffer
   }
}

This is a good start. It has some flaws, namely that it will stall and never figure out that data has stopped coming in if e.g. a corrupt packet comes over the wire followed by a valid one, or the serial cable is unplugged right in the middle of a packet. These flaws can be fixed by a combination of a well designed packet format, including for example a unique header, checksum and/or end sequence and timeouts that cause the receiver to reset its state.

I've had in mind some enhancements to address this very issue in ORSSerialPort itself. There's some discussion of this stuff in this issue on GitHub. Feel free to add your comments and suggestions on that issue if this is something you're interested in.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top