Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsolicited command 0x19 #13

Open
dbdbdb opened this issue Dec 12, 2021 · 3 comments
Open

Unsolicited command 0x19 #13

dbdbdb opened this issue Dec 12, 2021 · 3 comments

Comments

@dbdbdb
Copy link

dbdbdb commented Dec 12, 2021

Hi

The conbee device serial protocol sometime send an unsolicited command 0x19 that is not documented in

https://deconz.dresden-elektronik.de/raspbian/deCONZ-Serial-Protocol-en_1.21.pdf

Anyone that know what it is?

@manup
Copy link
Member

manup commented Dec 13, 2021

That's a Zigbee Green Power (ZGP) raw data indication frame

CMD_GP_DATA_INDICATION = 0x19

The frame is formatted identical to the ZGP specification (just a raw copy).
If it is helpful here is the C++ code how it is processed:

Note: Often the same frame is received 3 times this needs to be filtered by the application.

bool GpDataIndication::readFromStream(QDataStream &stream)
{
    Q_D(GpDataIndication);

    if (stream.atEnd()) { return false; }
    stream >> d->nwkFrameControl;

    // check frame type
    quint8 frameType = d->nwkFrameControl & 0x03;

    if ((frameType != GP_NwkDataFrame) &&
        (frameType != GP_NwkMaintenanceFrame))
    {
        return false;
    }

    // check green power protocol version
    if (((d->nwkFrameControl >> 2)& 0x03) != GP_NwkProtocolVersion)
    {
        return false;
    }

    // extended frame control
    if (d->nwkFrameControl & GP_NwkFrameControlExtensionFlag)
    {
        if (stream.atEnd()) { return false; }
        stream >> d->nwkExtFrameControl.byte;
    }
    else
    {
        d->nwkExtFrameControl.byte = 0;
    }

    // check supported application IDs
    switch (d->nwkExtFrameControl.bits.applicationId)
    {
    case 0: // 0b000 (GP)
    case 2: // 0b010 (GP)
    case 1: // 0b001 (LPED)
        break;

    default:
        return false;
    }

    // GPD SrcID field
    if ((frameType == GP_NwkDataFrame) && (d->nwkExtFrameControl.bits.applicationId == 0))
    {
        if (stream.atEnd()) { return false; }
        stream >> d->gpdSrcId;
    }
    else if ((frameType == GP_NwkMaintenanceFrame) && (d->nwkFrameControl & GP_NwkFrameControlExtensionFlag) && (d->nwkExtFrameControl.bits.applicationId == 0))
    {
        if (stream.atEnd()) { return false; }
        stream >> d->gpdSrcId;
    }
    else
    {
        d->gpdSrcId = 0; // unspecified
    }

    // frame counter filed
    // The presence and length of the Security frame counter field is dependent on the value of ApplicationID
    // and SecurityLevel (see A.1.4.1.3).
    d->frameCounter = 0;
    if (d->nwkFrameControl & GP_NwkFrameControlExtensionFlag)
    {
        switch (d->nwkExtFrameControl.bits.applicationId)
        {
        case 0: // 0b000 (GP)
        case 2: // 0b010 (GP)
        {
            switch (d->nwkExtFrameControl.bits.securityLevel)
            {
            case 0: // 0b00 No security
            case 1: // 0b01 1LSB of frame counter and short (2B) MIC only
                break;

            case 2: // 0b10 Full (4B) frame counter and full (4B) MIC only
            case 3: // 0b11 Encryption & full (4B) frame counter and full (4B) MIC
            {
                if (stream.atEnd()) { return false; }
                stream >> d->frameCounter;
            }
                break;

            default:
                break;
            }
        }
            break;

        case 1: // 0b001 (LPED)
            break;

        default:
            break;
        }
    }

    d->gpdCommandPayload.clear();

    switch (d->nwkExtFrameControl.bits.applicationId)
    {
    case 0: // 0b000 (GP)
    case 2: // 0b010 (GP)
    {
        if (stream.atEnd()) { return false; }
        stream >> d->gpdCommandId;

        quint8 byte;
        while (!stream.atEnd())
        {
            stream >> byte;
            d->gpdCommandPayload.append(byte);
        }
    }
        break;

    default:
        d->gpdCommandId = 0;
        break;
    }

    return true;
}

@dbdbdb
Copy link
Author

dbdbdb commented Dec 13, 2021

Thanks a lot Manuel. I really appreciate your work! I've been using the serial protocol for a couple of years and it has been working great for me. Time for me to read up on the ZGP specification that I've mostly managed to avoid so far! :-)

Do you want to keep the issue open? In case you want to update the documentation I mean.

@manup
Copy link
Member

manup commented Jan 5, 2022

Yes lets keep it open until this is completed in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants