Updated on 2023-10-18 GMT+08:00

Adaptation Development on the Device Side

Overview

Software OTA is implemented using the Huawei proprietary PCP protocol. You must perform adaptation development on devices in accordance with the interaction process defined in the protocol. The following describes how a device constructs a PCP request and response based on the software upgrade interactions between the IoT platform and device. This helps you better develop software upgrade functions on the devices.

PCP requests and responses have the same message structure, as shown below.

For details on each field in the message structure, see the table below.

Field

Type

Description

Start ID

WORD

The value is fixed at 0XFFFE.

Version

BYTE

The four most significant bits are reserved. The four least significant bits indicate the protocol version. Currently, the version is 1.

Message code

BYTE

Type of the request exchanged between the platform and device. The message code of a response is the same as that of the request. The following message codes have been defined:

  • 0-18: reserved
  • 19: device version query
  • 20: software package notification
  • 21: software package download
  • 22: download result reporting
  • 23: upgrade execution
  • 24: upgrade result reporting
  • 25-127: reserved

Check code

WORD

CRC16 check value calculated from the start ID to the last byte of the data zone. Before the calculation, this field is set to 0. The result is then written to the field after the CRC16 calculation.

NOTE:

CRC16 algorithm: CRC16/CCITT x16+x12+x5+1

Data zone length

WORD

Length of the data zone.

Data zone

BYTE[n]

Variable length, which is defined by each instruction. For details, see the definitions of the request and response corresponding to each instruction.

Data Type

Description

BYTE

Unsigned 1-byte integer

WORD

Unsigned 2-byte integer

DWORD

Unsigned 4-byte integer

BYTE[n]

Hexadecimal number of n bytes

STRING

String

Query on the Device Version

In the software upgrade process, the platform delivers a version query request to the device and the device responds to the request. (The process below includes only the PCP interactions between the platform and device. For details on the complete software upgrade process, see Software Upgrade for Devices Using LwM2M over CoAP.)

Message Sent by the Platform

In accordance with the PCP message structure, the platform fills each field in the request as follows:

  • Start ID: The value is fixed at the first two bytes of a message stream, that is, FFFE.
  • Version: The value is a 1-byte integer and is fixed at 1 (hexadecimal value: 01).
  • Message code: The value is a 1-byte integer. The message code for device version query is 19 (hexadecimal value: 13).
  • Check code: The value is a 2-byte integer. The system sets the check code to 0000, calculates the complete message stream by using the CRC16 algorithm to obtain a new check code, and then replaces 0000 with the new code.
  • Data zone length: The value is a 2-byte integer, indicating the length of the data zone. Based on the structure of the data zone, a version query request has no data zone. Therefore, the length is 0000.
  • Data zone: indicates the data to be sent to the device. Based on the structure of the data zone, this message does not contain the data to send. The data zone field is null.

    Field

    Data Type

    Description

    No data zone

Therefore, the combined code stream is FFFE 01 13 0000 0000. This stream is calculated using the CRC16 algorithm to obtain check code 4C9A. (The platform provides CRC16 code examples based on Java and C.) Then, the generated check code is used to replace 0000 in the original code stream to obtain FFFE 01 13 4C9A 0000. This code stream is sent by the platform to the device to query its version.

Message Sent by the Device

After receiving the version query request from the platform, the device returns the query result. The fields in the response are as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 13 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 17 bytes (hexadecimal value: 0011).
  • Data zone: Based on the structure of the data zone, the result code of successful processing is 00. If the version is V0.9, which is converted to ASCII characters 56302E39. The data type of the version is BYTE[16], which indicates 16 bytes. The version 56302E39 has only 4 bytes. Therefore, 0 is appended to obtain 56302E39000000000000000000000000. The data zone is 0056302E39000000000000000000000000.

    Field

    Data Type

    Description

    Result code

    BYTE

    The value is 0X00, indicating that the processing was successful.

    Current version

    BYTE[16]

    The version is described using ASCII characters. If there are not enough available digits, 0X00 is appended.

The combined code stream is FFFE 01 13 0000 0011 0056302E39000000000000000000000000. The check code after CRC16 calculation is 8DE3. Therefore, the device returns the code stream FFFE 01 13 8DE3 0011 0056302E39000000000000000000000000 to the platform.

Notification of a New Software Package

After obtaining the software version, the platform notifies the device of the software package of the new version.

Message Sent by the Platform

In accordance with the PCP message structure, the platform fills each field in the notification as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: Based on the message code, the message code of the new software package notification is 20 (hexadecimal value: 14).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 22 bytes (hexadecimal value: 0016).
  • Data zone:
    • Target version: The value consists of 16 bytes. If the target version is v1.0, the hexadecimal value appended with 0 is 56312E30000000000000000000000000.
    • Upgrade package segment size: The value consists of two bytes. You can manually enter the size of the upgrade package segment when uploading the software package. The default value is 500 bytes. The size ranges from 32 bytes to 500 bytes. For example, if the value is 500 bytes, the hexadecimal value is 01F4.
    • Number of upgrade package segments: The value consists of two bytes. The value is obtained by rounding up the result of the software package size divided by the segment size. If the software package size is 500 bytes, the number of segments is 1 (hexadecimal value: 0001).
    • Check code: The value consists of two bytes. This field has been deprecated. The fixed value is 0000.

      Field

      Data Type

      Description

      Target version

      BYTE[16]

      The version is described using ASCII characters. If there are not enough available digits, 0X00 is appended.

      Upgrade package segment size

      WORD

      Size of each segment.

      Number of upgrade package segments

      WORD

      Number of upgrade package segments.

      Check code

      WORD

      The value is fixed at 0000.

    The combined code stream is FFFE 01 14 0000 0016 56312E30000000000000000000000000 01F4 0001 0000. The check code after CRC16 calculation is 02F7. Therefore, the code stream in the message sent by the platform to instruct the device to download the new software package is FFFE 01 14 02F7 0016 56312E3000000000000000000000000001F400010000.

    Message Sent by the Device

    After receiving the notification, the device returns a response to the platform, indicating whether to allow the upgrade. The fields in the response are as follows:

    • Start ID: The value is fixed at FFFE.
    • Version: The value is fixed at 01.
    • Message code: The value is 14 (the same as that in the request).
    • Check code: The value 0000 is used before CRC16 calculation.
    • Data zone length: In accordance with the data type of the fields in the data zone, the length is 1 byte (hexadecimal value: 0001).
    • Data zone: The device responds to the new software package notification based on the actual situation. In this example, the device responds with "The upgrade is allowed". The data zone is 00. The other result codes must be adapted accordingly.

      Field

      Data Type

      Description

      Result code

      BYTE

      0X00: The upgrade is allowed.

      0X01: The device is in use.

      0X02: The signal is weak.

      0X03: The latest version is in use.

      0X04: The battery power is low.

      0X05: The remaining space is insufficient.

      0X09: The memory is insufficient.

      0X7F: An internal error has occurred.

    The combined code stream is FFFE 01 14 0000 0001 00. The check code after CRC16 calculation is D768. Therefore, the code stream in the message returned by the device is FFFE 01 14 D768 000100.

Downloading the Software Package

After the platform notifies the device of the new software package, the device requests to download the package according to the sequence number of each segment.

Message Sent by the Device

The device sends the first message to the platform to request packet segmentation. In accordance with the PCP message structure, the device fills each field in the first message as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: In accordance with the message code, the message code for requesting the software package is 21 (hexadecimal value: 15).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 18 bytes (hexadecimal value: 0012).
  • Data zone: The target version is the version in the notification delivered by the platform, v1.0 (hexadecimal value: 56312E30000000000000000000000000). The segment sequence number is 0 (hexadecimal value: 0000).

    Field

    Data Type

    Description

    Target version

    BYTE[16]

    The version is described using ASCII characters. If there are not enough available digits, 0X00 is appended.

    Segment sequence number

    WORD

    Sequence number of the requested segment. The value starts from 0. The total number of segments is obtained by rounding up the result of the software package size divided by the segment size. The device can save the received segments and request for the missing segments next time. Resumable download is supported.

The combined code stream is FFFE 01 15 0000 0012 56312E300000000000000000000000000000. The check code after CRC16 calculation is 5618. Therefore, the code stream in the first segment request sent by the device is FFFE 01 15 5618 0012 56312E300000000000000000000000000000.

For the code stream in other segment requests, only the segment sequence number needs to be replaced, and the check code needs to be replaced after CRC16 calculation. Details are not provided.

Message Sent by the Platform

After receiving a segment request, the platform delivers the segmented data to the device. The fields in the response to the first segment request are as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 15 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone: The result code is 00. The segment sequence number is 0000. The segment data depends on the content defined in the software package. If the software package content is HELLO, IoT SOTA!, the hexadecimal value is 48454C4C4F2C20496F5420534F544121, 16 bytes in total. When uploading a software package, you need to manually enter the size of the upgrade package segment, which is 500 bytes In this case, no 0 needs to be appended.

    Field

    Data Type

    Description

    Result code

    BYTE

    0X00: The processing was successful.

    0X80: The upgrade task does not exist.

    0X81: The specified segment does not exist.

    Segment sequence number

    WORD

    Sequence number of a returned segment.

    Segment data

    BYTE[n]

    Content of the segment. n indicates the segment size. If the result code is not 0, this field is not included.

  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 19 bytes (hexadecimal value: 0013).

The combined code stream is FFFE 01 15 0000 0013 00 0000 48454C4C4F2C20496F5420534F544121. The check code after CRC16 calculation is E107. The code stream in the message sent by the platform to respond to the first segment request is FFFE 01 15 E107 0013 00 0000 48454C4C4F2C20496F5420534F544121.

For the code stream in responses to the other segment requests, only the segment sequence number and segment data need to be replaced, and the check code needs to be replaced after CRC16 calculation. Details are not provided.

Download Result Reporting

After receiving all segments and assembling them, the device reports the download result to the platform.

Message Sent by the Device

In accordance with the PCP message structure, the device fills each field in the message as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 16 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 1 byte (hexadecimal value: 0001).
  • Data zone: carries the software package download results. For example, if the download was successful, the device reports 00.

    Field

    Data Type

    Description

    Download status

    BYTE

    0X00: The upgrade package has been downloaded.

    0X05: The remaining space is insufficient.

    0X06: The download timed out.

    0X07: The upgrade package failed to be verified.

    0X08: The upgrade package is not supported.

The combined code stream is FFFE 01 16 0000 0001 00. The check code after CRC16 calculation is 850E. The code stream in the download result message sent by the device is FFFE 01 16 850E 0001 00.

Message Sent by the Platform

After receiving the software package download results from the device, the platform returns a response. The fields in the response are as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 16 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 1 byte (hexadecimal value: 0001).
  • Data zone: If the processing is successful, 00 is returned. If the processing fails, 80 is returned. In this example, 00 is returned.

    Field

    Data Type

    Description

    Result code

    BYTE

    0X00: The processing was successful.

    0X80: The upgrade task does not exist.

The combined code stream is FFFE 01 16 0000 0001 00. The check code after CRC16 calculation is 850E. The code stream in the message sent by the platform is FFFE 01 16 850E 0001 00.

Upgrade Execution

After receiving the software package download result from the device, the platform instructs the device to start the upgrade.

Message Sent by the Platform

In accordance with the PCP message structure, the platform fills each field in the instruction as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 17 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 0 bytes (hexadecimal value: 0000).
  • Data zone: This field is not carried.

    Field

    Data Type

    Description

    No data zone

The combined code stream is FFFE 01 17 0000 0000. The check code after CRC16 calculation is CF90. The code stream in the message sent by the platform is FFFE 01 17 CF90 0000.

Message Sent by the Device

After receiving the upgrade execution message from the platform, the device responds to the message. The fields in the message are as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 17 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 1 byte (hexadecimal value: 0001).
  • Data zone: If the processing is successful, 00 is returned. For other processing results, see the data zone definition. In this example, 00 is returned.

    Field

    Data Type

    Description

    Result code

    BYTE

    0X00: The processing was successful.

    0X01: The device is in use.

    0X04: The battery power is low.

    0X05: The remaining space is insufficient.

    0X09: The memory is insufficient.

The combined code stream is FFFE 01 17 0000 0001 00. The check code after CRC16 calculation is B725. The code stream in the message returned by the device is FFFE 01 17 B725 0001 00.

Reporting the Upgrade Result

After executing the software upgrade, the device reports the upgrade result to the platform.

Message Sent by the Device

In accordance with the PCP message structure, the platform fills each field in an upgrade result message as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 18 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 17 bytes (hexadecimal value: 0011).
  • Data zone: carries the result code and current version. In this example, the result code is 00, indicating that the upgrade was successful. The current version is the same as the software version delivered by the platform, v1.0 (hexadecimal value: 56312E30000000000000000000000000).

    Field

    Data Type

    Description

    Result code

    BYTE

    0X00: The upgrade was successful.

    0X01: The device is in use.

    0X04: The battery power is low.

    0X05: The remaining space is insufficient.

    0X09: The memory is insufficient.

    0X0A: The upgrade package failed to be installed.

    0X7F: An internal error has occurred.

    Current version

    BYTE[16]

    Current version of the device.

The combined code stream is FFFE 01 18 0000 0011 0056312E30000000000000000000000000. The check code after CRC16 calculation is C7D2. The code stream in the upgrade result message reported by the device is FFFE 01 18 C7D2 0011 0056312E30000000000000000000000000.

Message Sent by the Platform

After receiving the upgrade result message, the platform responds to the device. The fields of each message are as follows:

  • Start ID: The value is fixed at FFFE.
  • Version: The value is fixed at 01.
  • Message code: The value is 18 (the same as that in the request).
  • Check code: The value 0000 is used before CRC16 calculation.
  • Data zone length: In accordance with the data type of the fields in the data zone, the length is 1 byte (hexadecimal value: 0001).
  • Data zone: If the processing is successful, 00 is returned. If the upgrade task does not exist, 80 is returned. In this example, 00 is returned.

    Field

    Data Type

    Description

    Result code

    BYTE

    0X00: The processing was successful.

    0X80: The upgrade task does not exist.

The combined code stream is FFFE 01 18 0000 0001 00. The check code after CRC16 calculation is AFA1. The code stream in the response returned by the platform is FFFE 01 18 AFA1 0001 00.

Now, the adaptation of the software upgrade is complete.

CRC16 Code Examples

Code example using the Java-based CRC16 algorithm:

public class CRC16 {

    /*
     * CCITT standard CRC16(1021) remainder table CRC16-CCITT ISO HDLC, ITU X.25, x16+x12+x5+1 polynomial
     * Polynomial generated in the case of highest order first: Gm=0x11021; polynomial generated in the case of lowest order first: Gm=0x8408. In this example, highest order first is used.
     */
    private static int[] crc16_ccitt_table = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
            0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252,
            0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
            0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509,
            0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
            0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7,
            0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
            0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e,
            0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
            0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4,
            0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
            0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3,
            0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
            0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589,
            0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
            0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0,
            0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
            0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e,
            0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
            0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45,
            0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
            0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 };

    /**
     *
     * @param reg_init
     *            initial value during the CRC
     * @param message
     *            check code
     * @return
     */
    private static int do_crc(int reg_init, byte[] message) {
        int crc_reg = reg_init;
        for (int i = 0; i < message.length; i++) {
            crc_reg = (crc_reg >> 8) ^ crc16_ccitt_table[(crc_reg ^ message[i]) & 0xff];
        }
        return crc_reg;
    }

    /**
     * Generate a CRC code based on the data.
     *
     * @param message
     *            byte data
     *
     * @return int verification code
     */
    public static int do_crc(byte[] message) {
        // The initial value of the CRC starts from 0x0000.
        int crc_reg = 0x0000;
        return do_crc(crc_reg, message);
    }
}

Code example using the C-based CRC16 algorithm:

/**
* CCITT standard CRC16(1021) remainder table CRC16-CCITT ISO HDLC, ITU X.25, x16+x12+x5+1 polynomial
* Polynomial generated in the case of highest order first: Gm=0x11021; polynomial generated in the case of lowest order first: Gm=0x8408. In this example, highest order first is used.
*/
const unsigned short crc16_table[256] = {
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

int do_crc(int reg_init, byte* data, int length)
{
    int cnt;
    int crc_reg = reg_init;
    for (cnt = 0; cnt < length; cnt++)
    {
        crc_reg = (crc_reg >> 8) ^ crc16_table[(crc_reg ^ *(data++)) & 0xFF];
    }
    return crc_reg;
}

int main(int argc, char **argv) 
{
    // FFFE011300000000 is represented by a byte array.
    byte message[8] = {0xFF,0xFE,0x01,0x13,0x00,0x00,0x00,0x00};
    // The initial value of the CRC starts from 0x0000.
    int a = do_crc(0x0000, message, 8);
    printf("a ==> %x\n", a);
}