Проблема кодирования BLE между iPhone и Arduino

Я работаю над устройством на базе Arduino, которое будет общаться через BLE с iPhone. Устройство основано на чипсете TI CC2541. Вот спецификация.

Мне нужно иметь возможность отправлять сообщения как с iPhone на устройство, так и с устройства обратно на iPhone. Сообщения представляют собой короткие строки ASCII. Устройство будет когда-либо обмениваться данными только с моим приложением для iPhone, поэтому нет реальной необходимости во всех вещах GATT и CoreBluetooth, но я новичок в Bluetooth, и это то, с чем я работаю. Если вы знаете способ добиться простой последовательной связи, минуя все леса CoreBluetooth/GATT, дайте мне знать!

Во всяком случае, я дошел до того, что смог отправлять сообщения с iPhone на Arduino. Но сообщения приходят искаженными. Для каждого полученного байта младшие 4 бита соответствуют младшим 4 битам отправленного байта. Но старшие 4 бита различаются.

Кто-нибудь знает кодировку, которая здесь используется? Или вы знаете способ просто отправить то, что я хочу отправить, без этой кодировки?

Вот подробности.

После подключения к моему устройству BT я перебираю все службы, характеристики и дескрипторы. Вот код для этого:

#pragma mark - CBCentralManagerDelegate

// CBCentralManagerDelegate - This is called with the CBPeripheral class as its main input parameter. This contains most of the information there is to know about a BLE peripheral.


// method called whenever the device state changes.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    // Determine the state of the peripheral
    if ([central state] == CBCentralManagerStatePoweredOff) {
        NSLog(@"CoreBluetooth BLE hardware is powered off");
    }
    else if ([central state] == CBCentralManagerStatePoweredOn) {
        NSLog(@"CoreBluetooth BLE hardware is powered on and ready");
        
        //  This could pass a list of services, but we will just check all BT devices found, at least for now...
        
        [self.BTManager scanForPeripheralsWithServices:nil options:nil];
    }
    else if ([central state] == CBCentralManagerStateUnauthorized) {
        NSLog(@"CoreBluetooth BLE state is unauthorized");
    }
    else if ([central state] == CBCentralManagerStateUnknown) {
        NSLog(@"CoreBluetooth BLE state is unknown");
    }
    else if ([central state] == CBCentralManagerStateUnsupported) {
        NSLog(@"CoreBluetooth BLE hardware is unsupported on this platform");
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
    if ([localName length] > 0 && [localName isEqualToString: BTName]) {
        
        // Connect to the borg.  Note the RSSI parameter above.  This is the signal strength.  Might come in handy!
        NSLog(@"Found our device %@", localName);
        [self.BTManager stopScan];
        self.thePeripheral = peripheral;
        peripheral.delegate = self;
        [self.BTManager connectPeripheral:peripheral options:nil];
    }
}


// method called whenever you have successfully connected to the BLE peripheral
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    peripheral.delegate = self;
    [peripheral discoverServices:nil];
    
    NSString *connected = [NSString stringWithFormat:@"Connected: %@", peripheral.state == CBPeripheralStateConnected ? @"YES" : @"NO"];
    NSLog(@"Connected to peripheral %@?  %@", peripheral.UUID, connected);
}


#pragma mark - CBPeripheralDelegate

// CBPeripheralDelegate - Invoked when you discover the peripheral's available services.
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    // Enumerate through all services on the connected peripheral.
    for (CBService * service in [peripheral services])
    {
        NSLog(@"Found service %@, %s", service.UUID, (service.isPrimary) ? "is primary" : "is secondary");
        
        // FFE0 is the service we will use to read/write
        if ([[service.UUID UUIDString] isEqualToString:@"FFE0"])
            self.txrxService = service;
        
        // Discover all characteristics for this service.
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

// Invoked when you discover the characteristics of a specified service.
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    // Enumerate through all services on the connected peripheral.
    for (CBCharacteristic * character in [service characteristics])
    {
        // FFE1 is the characteristic we will use to read/write
        if ([[character.UUID UUIDString] isEqualToString:@"FFE1"])
            self.txrxCharacteristic = character;
        
        NSLog(@"Service %@ has characteristic %@", service.UUID, character.UUID);
        // Discover all descriptors for each characteristic.
        [peripheral discoverDescriptorsForCharacteristic:character];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
    for (CBDescriptor* descriptor in characteristic.descriptors) {
        NSLog(@"Found descriptor %@ for characteristic %@", descriptor.UUID, characteristic.UUID);
    }

}

// Invoked when you retrieve a specified characteristic's value, or when the peripheral device notifies your app that the characteristic's value has changed.
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
}

И вот результат:

Found service Device Information, is primary
Found service FFE0, is primary
Service Device Information has characteristic System ID
Service Device Information has characteristic Model Number String
Service Device Information has characteristic Serial Number String
Service Device Information has characteristic Firmware Revision String
Service Device Information has characteristic Hardware Revision String
Service Device Information has characteristic Software Revision String
Service Device Information has characteristic Manufacturer Name String
Service Device Information has characteristic IEEE Regulatory Certification
Service Device Information has characteristic PnP ID
Service FFE0 has characteristic FFE1
Found descriptor Client Characteristic Configuration for characteristic FFE1
Found descriptor Characteristic User Description for characteristic FFE1

(Вопрос — обратите внимание, что я печатаю UUID, но это не UUID, а описательные строки. Что с этим делать?)

Несколько произвольно я выбираю службу FFE0, характеристику FFE1, чтобы использовать ее для отправки моих последовательных данных.

Вот некоторый тестовый код, который я использую для отправки всех печатных символов ASCII на устройство:

// Test sending a range of ascii values
-(void)BTSendTest: (CBPeripheral*)peripheral forCharacteristic:(CBCharacteristic*)characteristic
{
    NSLog(@"Sending to peripheral: %@ characteristic: %@", peripheral, characteristic.UUID);
    
    for (int asciiCode = 32, i=0; asciiCode < 126; asciiCode++, i++) {
        NSString *string = [NSString stringWithFormat:@"%c", asciiCode];
        
        NSLog(@"%d) sending <%@> 0x%x", i, string, asciiCode);
        
        NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding];
        if(characteristic.properties & CBCharacteristicPropertyWriteWithoutResponse)
            [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
        else
            [peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
}

И вот результат этого:

Sending to peripheral: <CBPeripheral: 0x156b1e60, identifier = 91DCFDD7-767E-65B7-6A66-48B5C7555CDC, name = TestDevice, state = connected> characteristic: FFE1
0) sending < > 0x20
1) sending <!> 0x21
2) sending <"> 0x22
3) sending <#> 0x23
4) sending <$> 0x24
5) sending <%> 0x25
6) sending <&> 0x26
7) sending <'> 0x27
8) sending <(> 0x28
9) sending <)> 0x29
10) sending <*> 0x2a
11) sending <+> 0x2b
12) sending <,> 0x2c
13) sending <-> 0x2d
14) sending <.> 0x2e
15) sending </> 0x2f
16) sending <0> 0x30
17) sending <1> 0x31
18) sending <2> 0x32
19) sending <3> 0x33
20) sending <4> 0x34
21) sending <5> 0x35
22) sending <6> 0x36
23) sending <7> 0x37
24) sending <8> 0x38
25) sending <9> 0x39
26) sending <:> 0x3a
27) sending <;> 0x3b
28) sending <<> 0x3c
29) sending <=> 0x3d
30) sending <>> 0x3e
31) sending <?> 0x3f
32) sending <@> 0x40
33) sending <A> 0x41
34) sending <B> 0x42
35) sending <C> 0x43
36) sending <D> 0x44
37) sending <E> 0x45
38) sending <F> 0x46
39) sending <G> 0x47
40) sending <H> 0x48
41) sending <I> 0x49
42) sending <J> 0x4a
43) sending <K> 0x4b
44) sending <L> 0x4c
45) sending <M> 0x4d
46) sending <N> 0x4e
47) sending <O> 0x4f
48) sending <P> 0x50
49) sending <Q> 0x51
50) sending <R> 0x52
51) sending <S> 0x53
52) sending <T> 0x54
53) sending <U> 0x55
54) sending <V> 0x56
55) sending <W> 0x57
56) sending <X> 0x58
57) sending <Y> 0x59
58) sending <Z> 0x5a
59) sending <[> 0x5b
60) sending <\> 0x5c
61) sending <]> 0x5d
62) sending <^> 0x5e
63) sending <_> 0x5f
64) sending <`> 0x60
65) sending <a> 0x61
66) sending <b> 0x62
67) sending <c> 0x63
68) sending <d> 0x64
69) sending <e> 0x65
70) sending <f> 0x66
71) sending <g> 0x67
72) sending <h> 0x68
73) sending <i> 0x69
74) sending <j> 0x6a
75) sending <k> 0x6b
76) sending <l> 0x6c
77) sending <m> 0x6d
78) sending <n> 0x6e
79) sending <o> 0x6f
80) sending <p> 0x70
81) sending <q> 0x71
82) sending <r> 0x72
83) sending <s> 0x73
84) sending <t> 0x74
85) sending <u> 0x75
86) sending <v> 0x76
87) sending <w> 0x77
88) sending <x> 0x78
89) sending <y> 0x79
90) sending <z> 0x7a
91) sending <{> 0x7b
92) sending <|> 0x7c
93) sending <}> 0x7d

Вот код на стороне Arduino, который получает сообщения BT:

#include <SoftwareSerial.h>

SoftwareSerial bt(A1, A0); // RX, TX

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  while (!Serial)
    ;
    
  Serial.println("BTTest");
  
  bt.begin(57600);
  
}

int rcvCount = 0;
void loop() {
  // put your main code here, to run repeatedly:
  if (bt.available()) {
    char _ch;
    while ((_ch = bt.read()) != -1) {
      unsigned char ch = (unsigned char)_ch;
      char str[2];
      str[0] = ch;
      str[1] = '\0';
      Serial.print(rcvCount++);
      Serial.print(") ");
      Serial.print(str);
      Serial.print("\t0x");
      Serial.println((unsigned int)(unsigned char)ch, HEX);
    };
  };
}

И вот результат этого:

BTTest
0) €	0x80
1) �	0x81
2) ‚	0x82
3) ƒ	0x83
4) „	0x84
5) …	0x85
6) †	0x86
7) §	0xA7
8) ˆ	0x88
9) ©	0xA9
10) ª	0xAA
11) «	0xAB
12) ¬	0xAC
13) ­	0xAD
14) ®	0xAE
15) ¯	0xAF
16) �	0x90
17) ‘	0x91
18) ’	0x92
19) “	0x93
20) ”	0x94
21) µ	0xB5
22) ¶	0xB6
23) ·	0xB7
24) ˜	0x98
25) ¹	0xB9
26) º	0xBA
27) »	0xBB
28) ¼	0xBC
29) ½	0xBD
30) ¾	0xBE
31) ¿	0xBF
32)  	0xA0
33) ¡	0xA1
34) ¢	0xA2
35) ƒ	0x83
36) ¤	0xA4
37) ¥	0xA5
38) †	0x86
39) ‡	0x87
40) ¨	0xA8
41) ©	0xA9
42) Š	0x8A
43) ‹	0x8B
44) Œ	0x8C
45) �	0x8D
46) ®	0xAE
47) �	0x8F
48) °	0xB0
49) ±	0xB1
50) ’	0x92
51) “	0x93
52) ´	0xB4
53) µ	0xB5
54) –	0x96
55) —	0x97
56) ¸	0xB8
57) ™	0x99
58) š	0x9A
59) ›	0x9B
60) œ	0x9C
61) �	0x9D
62) ž	0x9E
63) Ÿ	0x9F
64)  	0xA0
65) ¡	0xA1
66) ¢	0xA2
67) £	0xA3
68) ¤	0xA4
69) ¥	0xA5
70) ¦	0xA6
71) §	0xA7
72) ¨	0xA8
73) ©	0xA9
74) ª	0xAA
75) «	0xAB
76) ¬	0xAC
77) ­	0xAD
78) ®	0xAE
79) ¯	0xAF
80) °	0xB0
81) ±	0xB1
82) ²	0xB2
83) ³	0xB3
84) ´	0xB4
85) µ	0xB5
86) ¶	0xB6
87) ·	0xB7
88) ¸	0xB8
89) ¹	0xB9
90) º	0xBA
91) »	0xBB
92) ¼	0xBC
93) ½	0xBD

Итак, ... собрав все это вместе, похоже, что к отправляемым байтам добавляются шестнадцатеричные 40, 60 или 80 (десятичные 64, 96, 128). Но я не вижу закономерности.

Любые идеи?


person Dave    schedule 09.03.2015    source источник
comment
Вы должны использовать GATT с Core Bluetooth. Другого доступа к BLE на iOS нет. Похоже, вы неправильно конвертируете 8-битный ascii. Какую кодировку String вы используете при преобразовании NSData в NSString?   -  person Paulw11    schedule 09.03.2015
comment
Спасибо. Я пробовал несколько типов кодирования, в том числе NSUTF8StringEncoding. Дело в том, что если я проверяю полученный NSData в отладчике XCode перед его отправкой, значения выглядят нормально. Есть ли определенный тип кодирования, который я должен использовать?   -  person Dave    schedule 09.03.2015
comment
Возможно, вы могли бы показать какой-то код, но похоже, что проблема может быть на вашем периферийном устройстве, а не в iOS.   -  person Paulw11    schedule 09.03.2015
comment
Я могу показать код, если хотите, я его пропустил, потому что код довольно прост, и я не хотел слишком усложнять свой вопрос. Это устройство, которое я использую:   -  person Dave    schedule 09.03.2015
comment
img.banggood.com/file/products/   -  person Dave    schedule 09.03.2015
comment
Обновленный вопрос с кодом и дополнительной информацией.   -  person Dave    schedule 10.03.2015
comment
вы хотите записать содержимое контейнера данных на устройство, а не сам контейнер данных. изменить «[периферийное значение записи: данные» на «[периферийное значение записи: [байты данных]»   -  person CuriousRabbit    schedule 10.03.2015
comment
Спасибо, но это не то. writeValue принимает NSData*, а не (void*) (что и есть [байты данных]). Я все равно попробовал ваше предложение, и оно вылетает с EX_BAD_ACCESS.   -  person Dave    schedule 10.03.2015
comment
Хорошо, я добился некоторого прогресса. Я использовал скорость передачи 57600 на модуле BT. Я устанавливаю через АТ-команду. Если я сброшу скорость передачи данных до 9600, это сработает. Любые идеи?   -  person Dave    schedule 10.03.2015
comment
Используете ли вы программный серийный номер на своем Arduino?   -  person Paulw11    schedule 10.03.2015
comment
Да. Какую максимальную скорость передачи данных я могу использовать? Прости, я должен был подумать об этом. Поскольку каждое значение ascii постоянно читалось как одно и то же неправильное значение, я подумал, что это какая-то вещь с кодировкой. Мне не приходило в голову, что это были искаженные данные из-за слишком высокой скорости передачи данных.   -  person Dave    schedule 10.03.2015


Ответы (1)


попробуйте уменьшить скорость передачи данных для связи ble. вместо 57600 используйте 9600. Arduino имеет тенденцию работать нестабильно после скорости 19200 бод.

person arda30    schedule 18.07.2016