summaryrefslogtreecommitdiff
path: root/SmartDeviceLink/SDLProtocolMessageDisassembler.m
blob: 250a03c7271cbc7e700b2c22f022bb10d5673d86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//  SDLProtocolMessageDisassembler.m
//

#import "SDLProtocolMessageDisassembler.h"
#import "SDLProtocolHeader.h"
#import "SDLProtocolMessage.h"

NS_ASSUME_NONNULL_BEGIN

@implementation SDLProtocolMessageDisassembler


// Use to break up a large message into a sequence of smaller messages,
// each of which is less than 'mtu' number of bytes total size.
+ (NSArray<SDLProtocolMessage *> *)disassemble:(SDLProtocolMessage *)incomingMessage withLimit:(NSUInteger)mtu {
    // Questions:
    // What message IDs does the current system use? Same messageIDs? Same CorrelationIDs?
    // What gets simply copied from incoming header to created headers; and what needs adjustment?

    // How big is the message header?
    NSUInteger headerSize = incomingMessage.header.size;

    // The size of the message is too big to send in one chunk.
    // So lets break it up.
    // Just how big IS this message?
    NSUInteger incomingPayloadSize = (incomingMessage.data.length - headerSize);

    // How many messages do we need to create to hold that many bytes?
    // Note: this does NOT count the special first message which acts as a descriptor.
    NSUInteger numberOfMessagesRequired = ceil((float)incomingPayloadSize / (float)(mtu - headerSize));

    // And how many data bytes go in each message?
    NSUInteger numberOfDataBytesPerMessage = mtu - headerSize;

    // Create the outgoing array to hold the messages we will create.
    NSMutableArray<SDLProtocolMessage *> *outgoingMessages = [NSMutableArray arrayWithCapacity:numberOfMessagesRequired + 1];


    // Create the first message
    SDLProtocolHeader *firstFrameHeader = [incomingMessage.header copy];
    firstFrameHeader.frameType = SDLFrameTypeFirst;

    UInt32 payloadData[2];
    payloadData[0] = CFSwapInt32HostToBig((UInt32)incomingMessage.payload.length);
    payloadData[1] = CFSwapInt32HostToBig((UInt32)numberOfMessagesRequired);
    NSMutableData *firstFramePayload = [NSMutableData dataWithBytes:payloadData length:sizeof(payloadData)];
    firstFrameHeader.bytesInPayload = (UInt32)firstFramePayload.length;

    SDLProtocolMessage *firstMessage = [SDLProtocolMessage messageWithHeader:firstFrameHeader andPayload:firstFramePayload];
    outgoingMessages[0] = firstMessage;


    // Create the middle messages (the ones carrying the actual data).
    for (int n = 0; n < numberOfMessagesRequired - 1; n++) {
        // Frame # after 255 must cycle back to 1, not 0.
        // A 0 signals last frame.
        UInt8 frameNumber = (n % 255) + 1;

        SDLProtocolHeader *nextFrameHeader = [incomingMessage.header copy];
        nextFrameHeader.frameType = SDLFrameTypeConsecutive;
        nextFrameHeader.frameData = frameNumber;

        NSUInteger offsetOfDataForThisFrame = headerSize + (n * numberOfDataBytesPerMessage);
        NSData *nextFramePayload = [incomingMessage.data subdataWithRange:NSMakeRange(offsetOfDataForThisFrame, numberOfDataBytesPerMessage)];
        nextFrameHeader.bytesInPayload = (UInt32)nextFramePayload.length;

        SDLProtocolMessage *nextMessage = [SDLProtocolMessage messageWithHeader:nextFrameHeader andPayload:nextFramePayload];
        outgoingMessages[n + 1] = nextMessage;
    }


    // Create the last message
    SDLProtocolHeader *lastFrameHeader = [incomingMessage.header copy];
    lastFrameHeader.frameType = SDLFrameTypeConsecutive;
    lastFrameHeader.frameData = SDLFrameInfoConsecutiveLastFrame;

    NSUInteger numberOfMessagesCreatedSoFar = numberOfMessagesRequired - 1;
    NSUInteger numberOfDataBytesSentSoFar = numberOfMessagesCreatedSoFar * numberOfDataBytesPerMessage;
    NSUInteger numberOfDataBytesInLastMessage = incomingPayloadSize - numberOfDataBytesSentSoFar;
    NSUInteger offsetOfDataForLastFrame = headerSize + numberOfDataBytesSentSoFar;
    NSData *lastFramePayload = [incomingMessage.data subdataWithRange:NSMakeRange(offsetOfDataForLastFrame, numberOfDataBytesInLastMessage)];
    lastFrameHeader.bytesInPayload = (UInt32)lastFramePayload.length;

    SDLProtocolMessage *lastMessage = [SDLProtocolMessage messageWithHeader:lastFrameHeader andPayload:lastFramePayload];
    outgoingMessages[numberOfMessagesRequired] = lastMessage;

    return outgoingMessages;
}

@end

NS_ASSUME_NONNULL_END