Author Topic: IOS APPS in swift language  (Read 21979 times)

notsolinear

  • RFduino Jr. Member
  • **
  • Posts: 52
  • Karma: +3/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #30 on: December 14, 2014, 09:25:02 PM »
I'm a bit late to the discussion, but for what it's worth I have a few tips:

Personally I've left most of my NSData work in Obj-C and used Swift for everything else. The obnoxiously verbose "unsafe" types is a clue that direct pointer manipulation is frowned upon in Swift.

Perhaps this was already established, but I've never come across any need to fix endianness between RFduino and iOS, whether using Obj-C or Swift.

One great trick for parsing out multiple values from a transmission is to use C structs. It's basically just all the different variables concatenated together in memory so it's very easy to transmit/receive them in a batch. It also makes for friendly getters/setters on both sides.  There's one trick, which is to declare with the "__attribute__((packed))" otherwise on the iOS side things won't line up properly.

RFduino side (sending)
Code: [Select]
typedef struct __attribute__((packed)) {
 
  uint8_t someInt;
  float someFloat;
  int32_t anotherInt;

} TransmissionPacket;

TransmissionPacket newPacket;

newPacket.someInt = 224;
newPacket.someFloat = 1.234;
newPacket.anotherInt = 1234;

char *txBuffer = (char *) &newPacket;
RFduinoBLE.send(txBuffer, sizeof(TransmissionPacket)) //  (NOTE: Must be <= 20 bytes)


iOS side, in Swift (receiving):
Code: [Select]
var newPacket: TransmissionPacket!
data.getBytes(&newPacket, length: sizeof(TransmissionPacket))

println(newPayload.someInt)

maverik0106

  • RFduino Jr. Member
  • **
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #31 on: December 17, 2014, 07:01:35 PM »
Hi Notsolinear,

Thanks for the response, I apologize for the late thanks... So that's a neat trick to set the RFDuino for proper data sending to iOS, that's great to know...

I was just using the regular sendFloat function to send data raw like that....

And although I have't found any problems so far receiving the data, it will sure be useful when I'm trying to send these values with different variables and input/outputs...

I would like to ask you how is it that I can separate the 3 different values you packed into the RFDuino packet inside iOS? I'm assuming it has to do with the variable type transmission packet in iOS but is it set like a struct which will enumerate the different bytes somehow?

Sorry was this a typo: println(newPayload.someInt)? newPayload you meant to say newPacket? therefore I could techincally say println(newPacket.someFloat) as well? that's quite something! but then I would have to know the variables names a BLE module has been sending me no?

Or can I println(newPacket) and it would enumerate the properties inside newPacket i.e. someInt, someFloat, anotherInt...??

I will look into it for sure and thanks!

notsolinear

  • RFduino Jr. Member
  • **
  • Posts: 52
  • Karma: +3/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #32 on: December 17, 2014, 08:40:32 PM »
I would like to ask you how is it that I can separate the 3 different values you packed into the RFDuino packet inside iOS? I'm assuming it has to do with the variable type transmission packet in iOS but is it set like a struct which will enumerate the different bytes somehow?

Sorry was this a typo: println(newPayload.someInt)? newPayload you meant to say newPacket? therefore I could techincally say println(newPacket.someFloat) as well? that's quite something! but then I would have to know the variables names a BLE module has been sending me no?

Or can I println(newPacket) and it would enumerate the properties inside newPacket i.e. someInt, someFloat, anotherInt...??

You're correct, that last line was a typo.  Yes, you can simply access the variable properties by name and it will work. I think your question would have been answered if I'd written out a full demo app for both RFduino and iOS but I was just free-handing it in the reply. The key is that you also include that struct definition in the Xcode project, that's how the compiler knows the same data type as used in RFduino. My convention is to have a "data_types.h" file in my Arduino project which I drag into my Xcode project (de-selecting "copy" so it references the original).  That way both projects always have the latest data structures.  If you're using Swift you'll need to make sure you have a "bridging" header file that #include's the data_types.h file. The example code I posted was assuming that kind of a setup.

As far as enumerating the properties? You might get lucky in Swift since it's translating the struct into an equivalent Swift datatype automagically. I have a hazy recollection that at least the debugger can give a textual representation of the whole thing. Just being able to access properties by name is a huge plus as it allows the compiler to help catch errors and check types rather than having to do a lot of manual casting of data types.

When I get some more free time I plan to package up some code I've tested fairly extensively on my own projects which takes this to the next level:  It supports sending structs/payloads that are longer than the 20 byte limit per transmission with automatic reconstruction on the other side and checksumming for integrity. It also has a rudimentary model for identifying transmissions by packet type. That stuff becomes important as soon as your project becomes complex enough that you need to transmit more than 20bytes at a time.

maverik0106

  • RFduino Jr. Member
  • **
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #33 on: December 17, 2014, 08:56:20 PM »
Thanks for the clarification!

Well as far as enumerating if you're saying that we have to include the struct definition in the project then there's no point in seeing the struct's properties whatsoever since we'd know what variable names to use. I thought it would "magically" send the actual struct definition within the packet function...

I would have been quite impressed :) or did you mean that we have to include the struct definition of the data types I'm sorry I just re-read the first part... if swift does magically send the struct definition of the variables then I'm quite impressed... I'll give this a try later this week! quite excited to test this... Not 100% on how to do it, but google and stackoverflow are my friends :)

I'm sure I speak for many that we're excited to see what you came up with for sending data size packets of 20+ bytes! althought I thought it was 16 bytes? meh potato potata lol...

Thanks for the clarification!

notsolinear

  • RFduino Jr. Member
  • **
  • Posts: 52
  • Karma: +3/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #34 on: December 17, 2014, 09:44:00 PM »
Well as far as enumerating if you're saying that we have to include the struct definition in the project then there's no point in seeing the struct's properties whatsoever since we'd know what variable names to use. I thought it would "magically" send the actual struct definition within the packet function...

I would have been quite impressed :) or did you mean that we have to include the struct definition of the data types I'm sorry I just re-read the first part... if swift does magically send the struct definition of the variables then I'm quite impressed... I'll give this a try later this week! quite excited to test this... Not 100% on how to do it, but google and stackoverflow are my friends :)

No, you have to manually identify the data type on both sides (RFduino and iOS), by including that data_types.h in both.  What goes across the air is just the raw payload bytes, it's not "self describing". You can think of the struct as like a map to identify which bytes in the collection are what type and have what name. You need the map on the RFduino side to know how to put them in the right order and you need the map on the iOS side to identify them. To support sending multiple data types I use the first two bytes to identify the packet type and then use a switch statement to cast the received data into the correct struct. Once I get that library packaged up it will have a demo.

Perhaps a difference over the term enumeration.  I'm using it in the Obj-C sense where you can "enumerate" a data type like an array and automatically loop over all its members. I thought you were asking if we can enumerate/loop over all the properties of the struct, which I don't think is possible in C but may be in Swift.

maverik0106

  • RFduino Jr. Member
  • **
  • Posts: 59
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #35 on: December 18, 2014, 10:05:45 AM »
Yeah I thought so, I was using enumerate in the context of listing the objects in the struct, or printing them out in a list.. sorry about the confusion.

Thanks!

johncohn

  • RFduino Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #36 on: January 24, 2015, 06:43:09 AM »
Reading through this post i was hoping i'd somewhere find a link to a 'hello world' example for swift meets rfduino. Does such a thing exist yet ? Im looking for a swift example that opens up a connection to the rfduino, reads a value and dumps it to the ios console. Has anyone seen something like that ? it looked like MrWillJackson was pretty close.. but never saw the finished code. I'm not lazy.. just want to build on the sh0olders of giants :-) Thanks !
-jc

lik

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #37 on: February 01, 2015, 11:49:59 AM »
The nRF8001 sample code from the github posted by mrwilljackson in reply#6 is almost the finished code. The only thing left is to change those UUIDs as mrwilljackson posted.

However I encounter a problem. I can connect to the device and discover RX/TX services. However the hardware revision string is not read correctly. Somehow I wonder if my RFduino should have a different hardwareRevisionStringUUID. I used 2220 following mrwilljackson's post.

notsolinear

  • RFduino Jr. Member
  • **
  • Posts: 52
  • Karma: +3/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #38 on: February 06, 2015, 06:32:38 PM »
FYI: I've posted a sort of "pre-release" of a Swift-native demo iOS app and accompanying RFduino sketch demonstrating the transfer of arbitrarily large structured data. Can't send from iOS to RFduino yet, but sending from RFduino works. I would love to hear some feedback as to how this fits with people's needs to guide me as I revise it.

https://github.com/cconway/RFduinoUBP

mrwilljackson

  • RFduino Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #39 on: February 25, 2015, 02:20:34 AM »
The nRF8001 sample code from the github posted by mrwilljackson in reply#6 is almost the finished code. The only thing left is to change those UUIDs as mrwilljackson posted.

However I encounter a problem. I can connect to the device and discover RX/TX services. However the hardware revision string is not read correctly. Somehow I wonder if my RFduino should have a different hardwareRevisionStringUUID. I used 2220 following mrwilljackson's post.

Hi jc,

I was looking for solution in swift to read floating point values sent from the rfduino (not text characters), I've just come back to look into this once more and the following works, and outputs the values sent to the log. HTH!

go and grab this project from Github - https://github.com/MichMich/nRF8001-Swift#properties

open NRFManager.swift and replace the following:
Code: [Select]
// MARK: Class Methods
extension UARTPeripheral {
    class func uartServiceUUID() -> CBUUID {
        return CBUUID(string:"2220")
    }
   
    class func txCharacteristicsUUID() -> CBUUID {
        return CBUUID(string:"2222")
    }
   
    class func rxCharacteristicsUUID() -> CBUUID {
        return CBUUID(string:"2221")
    }
   
    class func deviceInformationServiceUUID() -> CBUUID{
        return CBUUID(string:"2220")
    }
   
    class func hardwareRevisionStringUUID() -> CBUUID{
        return CBUUID(string:"2220")
    }
}

Then goto line 435 in the same file and locate
Code: [Select]
private func peripheral(peripheral: CBPeripheral!, didUpdateValueForCharacteristic characteristic: CBCharacteristic!, error: NSError!)after the existing line
Code: [Select]
delegate.didReceiveData(characteristic.value)add this
Code: [Select]
/////////////// converts the hex value back into floating point number /////////////////
                var bin32:UInt32 = 0
                characteristic.value.getBytes(&bin32, range: NSRange(location: 0,length:characteristic.value.length))
                var floatVal:Float = unsafeBitCast(bin32, Float.self)
                println(floatVal)

Then build and run, and your iDevice should pick up the default rfduino BLE broadcast, allow you to connect and receive the updated characteristics (the floating point numbers). Good luck!


wiesnerhealth

  • RFduino Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #40 on: March 23, 2015, 11:40:55 PM »
WOOWW, Thanks so much for this, I have connected the RFduino and it actually works really good.
I have a question as Im a total newbie with programming, how can I access the floatVal variable from the ViewController.swift, I want to make something like the Temperature App by updating a Label in the UI. unfortunately i haven't been able to access this variable.

Thank you much for your help.

notsolinear

  • RFduino Jr. Member
  • **
  • Posts: 52
  • Karma: +3/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #41 on: March 24, 2015, 10:06:59 PM »
I have a question as Im a total newbie with programming, how can I access the floatVal variable from the ViewController.swift, I want to make something like the Temperature App by updating a Label in the UI. unfortunately i haven't been able to access this variable.

If I'm understanding your question, then probably the Unambitious Binary Protocol (UBP) project of mine is a bit overkill for your need. If you know you'll only ever send a float value for a single measurement/parameter then you can do without a lot of the additional overhead.

On the other hand, there's nothing wrong with using the UBP project as a template either. Where I'd suggest you start is to go into the data_types.h file and change the MeasurementType "struct" to match your use-case. Maybe that means it just has a temperature float value and we'll add another integer we increment each time we send.

Code: [Select]
typedef struct __attribute__((packed)) {
 
  unsigned char serialNumber;
  float temperature;

} MeasurementType;

Now you'll need to remove the B, C, D... lines from the RFduino code and then set the values for your 'serialNumber' and 'temperature' properties you just defined in data_types.h.

Finally, in the Xcode project you'll similarly edit the MeasurementType lines to remove the B, C, D... references and replace them with your new 'serialNumber' and 'temperature' property names.  Autocomplete should help you out a bit. Once you're done with that you should be able to simply access the received values as  measurementPayload.temperature.

When you're feeling more ambitious you can experiment with changing the name of the struct to something other than "MeasurementType" or creating new struct types and payload IDs (in constants.h) for sending other types of messages. The ingredients are there for passing very rich, organized information.

wiesnerhealth

  • RFduino Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #42 on: March 26, 2015, 08:17:34 AM »
thanks a lot I will try to do that.

Esod

  • RFduino Newbie
  • *
  • Posts: 1
  • Karma: +0/-0
    • View Profile
Re: IOS APPS in swift language
« Reply #43 on: January 18, 2016, 09:14:24 AM »
Hello everyone,

I try to send the number "1" to my rfduino but all you propose don't work :( (i try this : https://github.com/MichMich/nRF8001-Swift with the modifications on the NRFManager.

In my viewcontroller, i try this
Quote
func sendData()
    {
        let data = "0x01"
        let result = self.nrfManager.writeString(data)
        log("⬆ Sent string: \(data) - Result: \(result)")
    }

But the message on my console log is :

Quote
NRFManager: Central Manager Did UpdateState
NRFManager: Powered on!
NRFManager: Scan for Peripherials
NRFManager: Did discover peripheral: Optional("RFduino")
NRFManager: Connect to Peripheral: <CBPeripheral: 0x145ba2a0, identifier = 9AAB31C2-E122-E8EB-5521-992B5D108AA7, name = RFduino, state = disconnected>
NRFManager: Did Connect Peripheral
NRFManager: Did connect peripheral: Optional("RFduino")
UARTPeripheral: Did connect
UARTPeripheral: Start service discovery: Optional("RFduino")
UARTPeripheral: Found correct service
UARTPeripheral: Did Discover Characteristics For Service: <CBService: 0x145a0d70, isPrimary = YES, UUID = 2220>
UARTPeripheral: Set up peripheral for use
UARTPeripheral: Found RX Characteristics
UARTPeripheral: Found TX Characteristics
NRFManager: Can't send string. No connection!
⬆ Sent string: 0x01 - Result: false

How can i send a number to my RFDuino ? :)

Thank's a lot :)