Пока все хорошо. Мне удалось установить связь TCP/IP с помощью CFStream.
Моя проблема: когда я отправляю какое-либо сообщение на OBDKey, ответом является точно такое же сообщение.
Я думаю, что ошибочный код находится где-то в методе потока приложения. Но я не могу этого понять.
Надеюсь, вы дадите мне совет.
Вот код:
Код: Выделить всё
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
NSInputStream *inputStream;
NSOutputStream *outputStream;
@implementation Communicator
@synthesize textField; // Gegenstück zu @property im .h File
@synthesize textView; // Gegenstück zu @property im .h File
- (IBAction)connectPressed:(id)sender {
host = @"192.168.0.74";
port = 23;
// Ausgabe
[self debugPrint:[NSString stringWithFormat:@"Setting up connection to %@ : %i", host, port]];
// Stream wird erzeugt mit Host, Port, Read & Write stream
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)(host), port, &readStream, &writeStream);
// Überprüfung ob Write Stream funktioniert
if (!CFWriteStreamOpen(writeStream)) {
[self debugPrint:[NSString stringWithFormat:@"Error, writeStream not open"]];
return;
}
// Methode open wird geöffnet
[self open];
[self debugPrint:[NSString stringWithFormat:@"Status of outputStream: %i", [outputStream streamStatus]]];
return;
}
// Hier werden sowohl der Output (Write)- als auch der Input (Read)-Stream geöffnet.
- (void)open {
[self debugPrint:[NSString stringWithFormat:@"Opening streams..."]];
// Da Automatic Reference Counting betrieben wird, muss eine __bridge Notation gesetzt werden um
// das Objekt hin und her verwenden zu können.
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
// RunLoop wird verwendet um input und output Objekte zu managen (Reihenfolgen usw.)
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
// Überprüfung ob beide Streams geöffnet wurden
if (!inputStream && !outputStream)
{
[self debugPrint:[NSString stringWithFormat:@"Error. Could not open streams!"]];
return;
}
//[self debugPrint:[NSString stringWithFormat:@"Streams are open"]];
}
// Disconnect Button wird gedrückt - Hierbei werden alle input und output streams geschlossen
// und RunLoops geschlossen
- (IBAction)disconnectPressed:(id)sender {
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream setDelegate:nil];
[outputStream setDelegate:nil];
inputStream = nil;
outputStream = nil;
[self debugPrint:[NSString stringWithFormat:@"Session closed!"]];
}
// Methode welche den eingegeben Text vom TextField in das TextView schreibt
- (IBAction)sendPressed:(id)sender {
// Hier wird überprüft ob eine Eingabe im textField erfolgt ist (ob Zeichen eingegeben wurden)
if ([[textField text] length] > 0) {
NSString *textFieldString = [textField text];
[self writeOut:(NSString *)textFieldString];
[self.textField endEditing:YES];
}
}
- (IBAction)clearViewPressed:(id)sender {
textView.text = nil;
}
// Methode in der Text formatiert im textView angezeigt werden kann
- (void)debugPrint:(NSString *)text {
textView.text = [textView.text stringByAppendingFormat: @"\n%@", text];
}
// Methode die Zuständig ist zum Stream handling
//NSStreamEventNone = 0
//NSStreamEventOpenCompleted = 1
//NSStreamHasBytesAvailable = 2
//NSStreamHasSpaceAvailable = 4
//NSStreamEventErrorOccurred = 8
//NSStreamEventEndEncountered = 16
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
if (stream.streamStatus == 2) {
[self debugPrint:[NSString stringWithFormat:@"Stream opened"]];
}
switch (event) {
case NSStreamEventHasSpaceAvailable: {
if (stream == outputStream) {
[self debugPrint:[NSString stringWithFormat:@"Ouput stream is ready!"]];
}
break;
}
case NSStreamEventHasBytesAvailable: {
if (stream == inputStream) {
[self debugPrint:[NSString stringWithFormat:@"Input stream is ready!"]];
uint8_t buf[1024];
unsigned int len = 0; // len wird nie negativ sein => unsigned
len = [inputStream read:buf maxLength:1024];
if (len > 0) {
NSMutableData* data = [[NSMutableData alloc] initWithLength:0];
// data wird mit Daten aus dem Buffer buf gefüttert (maximale Länge len)
[data appendBytes: (const void *)buf length:len];
// Erlaubt die Konvertierung eines Datenstrings in einen Characterstring
NSString *raw_data = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
// Sends raw_data to readIn method
[self readIn:raw_data];
}
}
break;
}
default: {
[self debugPrint:[NSString stringWithFormat:@"Stream is sending an Event: %u", event]];
break;
}
}
}
- (void)readIn:(NSString *)s {
[self debugPrint:[NSString stringWithFormat:@"Reading:"]];
[self debugPrint:[NSString stringWithFormat:@"%@", s]];
}
- (void)writeOut:(NSString *)string {
uint8_t *buf = (uint8_t *)[string UTF8String];
[outputStream write:buf maxLength:strlen((char *)buf)];
[self debugPrint:[NSString stringWithFormat:@"%s\r\n", buf]];
//[self debugPrint:[NSString stringWithFormat:@"Sent:"]];
//[self debugPrint:[NSString stringWithFormat:@"%@\r\n", string]];
}
@end
Я понял это: мне нужно отправить команды инициализирующего рукопожатия, чтобы начать фактическую связь (ATZ, ATSP0 и ATL1). Я сделал это в отдельном методе, который вызывается в процессе подключения приложения.
Подробнее здесь: https://stackoverflow.com/questions/232 ... nputstream
Мобильная версия