[Nanopb] String/Bytes type proto - Decode example code

Posted by [하늘이]
2020. 1. 30. 14:14 IT/C, C++
반응형

StringBytes Decode sample code


※ 관련글

  • Google Protobuf
  1. [Google Protobuf] For Java in Android Studio - 설치 및 proto 파일 컴파일
  2. [Google Protobuf] For Java in Android Studio - Gen Java 파일 Android Studio 적용
  3. [Google Protobuf] For Java in Android Studio - Basic example code 기본 소스 코드 사용 샘플
  4. [Google Protobuf] For C++ in Linux - Settings C++ 빌드 환경 만들기
  5. [Google Protobuf] For C++ in Linux - Basic example code 기본 소스 코드 사용 샘플
  • Nanopb Basic type value example
  1. [Nanopb for Google protobuf] Basic type proto sample
  2. [Nanopb for Google protobuf] Basic type proto sample - Sample proto file
  3. [Nanopb for Google protobuf] Basic type proto sample - Encode sample code
  4. [Nanopb for Google protobuf] Basic type proto sample - Decode sample code
  • Nanopb String / bytes value example
  1. [Nanopb for Google protobuf] String/Bytes type proto
  2. [Nanopb for Google protobuf] String/Bytes type proto - Sample proto file 
  3. [Nanopb for Google protobuf] String/Bytes type proto - Encode example code 1
  4. [Nanopb for Google protobuf] String/Bytes type proto - Encode example code 2
  5. [Nanopb for Google protobuf] String/Bytes type proto - Decode example code
  • Nanopb basic submsg example
  1. [Nanopb for Google protobuf] Sub message - Example proto file
  2. [Nanopb for Google protobuf] Sub message - Encode example code
  3. [Nanopb for Google protobuf] Sub message - Decode example code
  • Nanopb array submsg value example

  1. [Nanopb for Google protobuf] Array Sub message - Example proto file
  2. [Nanopb for Google protobuf] Array Sub message - Encode example code
  3. [Nanopb for Google protobuf] Array Sub message - Decode example code

Decode 방법은 encode 1 / 2 둘다 사용이 가능.

 

* proto 파일에 선언한 데이터를 획득하기 위한 구조체를 사용하여 데이터를 전달 받는다.

arg 에 구조체의 주소를 넘겨 callback 이 호출 될때 참조되도록 되어 있다.


* 구조체를 먼저 선언한다.

1
2
3
4
5
6
7
8
#define TestStrBtsStuctMaxLen 15
 
typedef struct{
    int32_t testInt32;
    char testString[TestStrBtsStuctMaxLen];
    byte testBytes[TestStrBtsStuctMaxLen];
    byte testBytesSize;
}TestStrBtsStuct;
cs

bytes 의 길이를 확인하기 위하여 testBytesSize 라는 변수하나를 더 추가하였다.


* Struct 변수의 데이터를 복사하거나 초기화 시키기 위한 함수를 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void initStruct(TestStrBtsStuct &testStrBtsSt){
    testStrBtsSt.testBytesSize = 0;
    memset(testStrBtsSt.testBytes, 0, TestStrBtsStuctMaxLen);
    memset(testStrBtsSt.testString,0, TestStrBtsStuctMaxLen);
}
 
// add a string to struct
void add_String(TestStrBtsStuct * testStrBtsSt, char* str, byte size)
{
    strncpy(testStrBtsSt->testString, str, (size >TestStrBtsStuctMaxLen ? TestStrBtsStuctMaxLen : size) );
}
 
// add a byteArray to struct
void add_ByteArr(TestStrBtsStuct * testStrBtsSt, uint8_t* buffer, byte size)
{
    testStrBtsSt->testBytesSize = size;
    memcpy(testStrBtsSt->testBytes, buffer, (size >TestStrBtsStuctMaxLen ? TestStrBtsStuctMaxLen : size));
}
cs

 


* Decode 시 호출 되는 callback api를 생성하고 등록한다.

String 타입의 데이터를 위한 Callback api 

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
bool decode_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
    uint8_t buffer[100= {0};
 
    Serial.print("decode_string start @@@");
    Serial.println("");
 
    if (stream == NULL){
        Serial.print("decode_string  stream null");
        Serial.println("");
        return false;
    }
 
    size_t len = stream->bytes_left;
 
    /* We could read block-by-block to avoid the large buffer... */
    if (len > sizeof(buffer) - 1){
        Serial.print("decode_string  size error:");
        Serial.print(len);
        Serial.println("");
        return false;
    }
 
    if (!pb_read(stream, buffer, len)){
        Serial.print("decode_string  failed:");
        Serial.print(PB_GET_ERROR(stream));
        Serial.println("");
        return false;
    }
 
    TestStrBtsStuct * dest = (TestStrBtsStuct*)(*arg);
    add_String(dest, (char*)buffer, len);
 
    return true;
}
cs

 


* Decode 시 호출 되는 callback api를 생성하고 등록한다.

Bytes 타입의 데이터를 위한 Callback api 

두 함수의 차이점은 마지막 decode 된 값을 struct 변수에 넣어주는 함수가 다른 것 외에 대동 소이하다.

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
bool decode_byteArr(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
    uint8_t buffer[100= {0};
 
    Serial.print("decode_byteArr start @@@");
    Serial.println("");
 
    if (stream == NULL){
        Serial.print("decode_byteArr  stream null");
        Serial.println("");
        return false;
    }
 
    size_t len = stream->bytes_left;
 
    /* We could read block-by-block to avoid the large buffer... */
    if (len > sizeof(buffer) - 1){
        Serial.print("decode_byteArr  size error:");
        Serial.print(len);
        Serial.println("");
        return false;
    }
 
    if (!pb_read(stream, buffer, len)){
        Serial.print("decode_byteArr  failed:");
        Serial.print(PB_GET_ERROR(stream));
        Serial.println("");
        return false;
    }
 
    TestStrBtsStuct * dest = (TestStrBtsStuct*)(*arg);
    add_ByteArr(dest, buffer, len);
 
    return true;
}
 
cs

 


* Decode main 함수를 구현한다. 위에서 만들어 놓은 callback api를 사용하게 된다.

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
void testDecodeTestStrBytesTypes(int encodeSize, uint8_t* buffer) {
 
    // 내부적으로 생성한 struct 타입의 변수를 사용하기 위하여 선언.
    TestStrBtsStuct testStruct;
    // Struct 변수 초기화 시킨다.
    initStruct(testStruct);
    //Decode 시키기 위한 inStream 생성
    pb_istream_t stream;
 
    /* Construct a pb_istream_t for reading from the buffer */
    stream = pb_istream_from_buffer(buffer, encodeSize);
 
    /* Uses _init_default to just make sure that the macro works. */
    TestStrBytesTypes msg = TestStrBytesTypes_init_default;
    /* [Optional] Fill with garbage to better detect initialization errors */
    memset(&msg, 0xAAsizeof(msg));
 
    //String 값을 decode 시킬 api를 callback에 등록한다.
    msg.testString.funcs.decode = &decode_string;
    //String callback api 호출 시 arg로 전달될 Struct 변수를 등록한다.
    msg.testString.arg = &testStruct;
 
    //bytes 값을 decode 시킬 api를 callback에 등록한다.
    msg.testBytes.funcs.decode = &decode_byteArr;
    //bytes callback api 호출 시 arg로 전달될 Struct 변수를 등록한다.
    msg.testBytes.arg = &testStruct;
 
    // pb decode 함수를 사용하여 bytes 를 객체화 시킨다. 실패 시 false 가 출력.
    // decode api를 호출 되면 pb내부적으로 위에서 등록한 callback api들이 호출 된다.
    if (!pb_decode(&stream, TestStrBytesTypes_fields, &msg)) {
        Serial.print("TestStrBytesTypes Decoding failed: ");
        Serial.print(PB_GET_ERROR(&stream));
        Serial.println("");
        return;
    } else {
        testStruct.testInt32 = msg.testInt32;
        //Decode 된 메시지 를 출력시켜 확인한다.
        //아래에서 출력 시키는 변수는 Proto Gen으로 생성된 메시지 변수가 아닌 내부 Struct 변수다.
        Serial.print("TestStrBytesTypes Decoding OK ");
        Serial.println("");
        Serial.print(" testInt32:");
        Serial.print(testStruct.testInt32);
        Serial.println("");
 
        Serial.print(" string:");
        Serial.print(testStruct.testString);
        Serial.println("");
 
        Serial.print(" ByteArr: ");
        // encode된 데이터 바이트 값 출력.
        for (int i = 0; i < testStruct.testBytesSize; i++) {
            Serial.print(testStruct.testBytes[i], 16);
            Serial.print(" ");
        }
        Serial.println("");
    }
 
}
 
cs


반응형