crsf-wg / crsf

MIT License
114 stars 7 forks source link

Find Channel #7

Closed Artem-N closed 5 months ago

Artem-N commented 7 months ago

I'm sorry, I just started to understand the radio control protocols, could you tell me how I can parse the channel numbers from which the commands come? as I understand they are encoded in the payload of the telemetry packet?

sk8board commented 7 months ago

It looks like packet channels are located in packet type 0x16 CRSF_FRAMETYPE_RC_CHANNELS_PACKED

Which states: The data is just 16x channels packed to 11 bits (LSB-first, little endian). [dest] 0x18 0x16 [channel00:11] [channel01:11] ... [channel15:11] [crc8]. Depending on the endianness of your platform, this struct may work to encode/decode the channels data:

https://github.com/crsf-wg/crsf/wiki/Packet-Types

Artem-N commented 7 months ago

It looks like packet channels are located in packet type 0x16 CRSF_FRAMETYPE_RC_CHANNELS_PACKED

Which states: The data is just 16x channels packed to 11 bits (LSB-first, little endian). [dest] 0x18 0x16 [channel00:11] [channel01:11] ... [channel15:11] [crc8]. Depending on the endianness of your platform, this struct may work to encode/decode the channels data:

https://github.com/crsf-wg/crsf/wiki/Packet-Types

Yep, you are right but I need to somehow get the channel numbers from this packet, now I am reading the following data "bytearray(b'\xc8\x18\x16\xe0\xf3\x1e+\xc0\xc7\nV\xb0\x82\x15\xac`\x05\x03\xc9\x07>\xf0\x81\x0f|\x96')" where format "[sync] [len] [type] [payload] [crc8]", and I need to get to this "x16" packet, or somehow decode it (but maybe it not encode) Thanks for helping :)

sk8board commented 7 months ago

At the bottom of CRSF_FRAMETYPE_RC_CHANNELS_PACKED it states the following:

The values are CRSF channel values (0-1984). CRSF 172 represents 988us, CRSF 992 represents 1500us, and CRSF 1811 represents 2012us. Example: All channels set to 1500us (992) ee 18 16 e0 3 1f f8 c0 7 3e f0 81 f 7c e0 3 1f f8 c0 7 3e f0 81 f 7c ad

I have tried to decode this example to find 992 (00000111110) repeating every 11 bits, but I do not see the pattern.

@CapnBry is your example correct? How does a person find a specific channel from the byte array?

CapnBry commented 7 months ago

Folks, this is not a "let's all learn how to program using a github issue tracker" forum.

@CapnBry is your example correct? How does a person find a specific channel from the byte array?

My brain breaks trying to 11 bit endian swap that, but 992 is 0x3e0 and that's right up in front there. The most platform agnostic way to read the channels is to shift them out. I made this quick example from our code:

//gcc 7.4.0

#include  <stdio.h>
#include <stdint.h>

static void UnpackChannels(uint8_t *buf, uint32_t * const dest)
{
    uint8_t const * const payload = (uint8_t const * const)buf;
    const unsigned numOfChannels = 16;
    const unsigned srcBits = 11;
    const unsigned dstBits = 32;
    const unsigned inputChannelMask = (1 << srcBits) - 1;

    // code from BetaFlight rx/crsf.cpp / bitpacker_unpack
    uint8_t bitsMerged = 0;
    uint32_t readValue = 0;
    unsigned readByteIndex = 0;
    for (uint8_t n = 0; n < numOfChannels; n++)
    {
        while (bitsMerged < srcBits)
        {
            uint8_t readByte = payload[readByteIndex++];
            readValue |= ((uint32_t) readByte) << bitsMerged;
            bitsMerged += 8;
        }
        //printf("rv=%x(%x) bm=%u\n", readValue, (readValue & inputChannelMask), bitsMerged);
        dest[n] = (readValue & inputChannelMask);
        readValue >>= srcBits;
        bitsMerged -= srcBits;
    }
}

int main(void)
{
    uint32_t dst[16];
    uint8_t src[] = { 
        0xe0, 0x3, 0x1f, 0xf8, 0xc0, 0x7, 0x3e, 0xf0, 0x81, 0xf, 0x7c, 0xe0, 0x3, 0x1f, 0xf8, 0xc0, 0x7, 0x3e, 0xf0, 0x81, 0xf, 0x7c, 0xad
    };
    UnpackChannels(src, dst);
    for (unsigned ch=0; ch<16; ++ch)
        printf("ch%02u=%u ", ch, dst[ch]);
    printf("\n");
    return 0;
}
ch00=992 ch01=992 ch02=992 ch03=992 ch04=992 ch05=992 ch06=992 ch07=992 ch08=992 ch09=992 ch10=992 ch11=992 ch12=992 ch13=992 ch14=992 ch15=992 
sk8board commented 7 months ago

Maybe opening the discussion section of this GitHub would prevent questions from entering the issue tracker? This would also allow other people who are following this GitHub repository to help and learn as a community.

Folks, this is not a "let's all learn how to program using a github issue tracker" forum.

@CapnBry I appreciate the excellent work you have done with ExpressLRS. With that said, the work-in-progress documentation that you are working on does leave many questions. A more in-depth example would help reduce questions.

Here is a more graphic demonstration of the CRSF_FRAMETYPE_RC_CHANNELS_PACKED example, ee 18 16 e0 3 1f f8 c0 7 3e f0 81 f 7c e0 3 1f f8 c0 7 3e f0 81 f 7c ad

Color change shows separation for each channel value 992 in 11 bits (01111100000) when using LSB, little endian.

image

NOTE: in CRSF_FRAMETYPE_RC_CHANNELS_PACKED, you state "11 bits (LSB-first, little endian)". I was tripped-up by the word "first". If only LSB was used, I would have understood how to correctly interpret the bits. When the word "first" was used with LSB, I assumed the bit order was changed to be 01234567 rather than 76543210.

This is why it is helpful to provide a more in-depth example. Please let me know if I can be helpful in some other way than asking questions :)

CapnBry commented 7 months ago

I'm trying my best, man :-D

All my docs come from "here's how things are implemented" and will take some time to transition into "here's how I think things are designed". I do not know how to describe buf[0] | ((buf[1] & 0x3) << 8) in words as easily as it can be described by code. It is the low bits first, followed by the high bits in the right position of the next byte. It isn't exactly "LSB-first little endian" but I do not know how to describe that in words. I'm not sure how to describe endianness with regard to values that span multiple bytes partially. I suspect the original TBS implementation was just the example struct, and it just so happened it worked out to be the correct bit order on both receiving and transmitting MCUs.

What sort of example would you like to see?

Artem-N commented 7 months ago

Folks, this is not a "let's all learn how to program using a github issue tracker" forum.

@CapnBry is your example correct? How does a person find a specific channel from the byte array?

My brain breaks trying to 11 bit endian swap that, but 992 is 0x3e0 and that's right up in front there. The most platform agnostic way to read the channels is to shift them out. I made this quick example from our code:

//gcc 7.4.0

#include  <stdio.h>
#include <stdint.h>

static void UnpackChannels(uint8_t *buf, uint32_t * const dest)
{
    uint8_t const * const payload = (uint8_t const * const)buf;
    const unsigned numOfChannels = 16;
    const unsigned srcBits = 11;
    const unsigned dstBits = 32;
    const unsigned inputChannelMask = (1 << srcBits) - 1;

    // code from BetaFlight rx/crsf.cpp / bitpacker_unpack
    uint8_t bitsMerged = 0;
    uint32_t readValue = 0;
    unsigned readByteIndex = 0;
    for (uint8_t n = 0; n < numOfChannels; n++)
    {
        while (bitsMerged < srcBits)
        {
            uint8_t readByte = payload[readByteIndex++];
            readValue |= ((uint32_t) readByte) << bitsMerged;
            bitsMerged += 8;
        }
        //printf("rv=%x(%x) bm=%u\n", readValue, (readValue & inputChannelMask), bitsMerged);
        dest[n] = (readValue & inputChannelMask);
        readValue >>= srcBits;
        bitsMerged -= srcBits;
    }
}

int main(void)
{
    uint32_t dst[16];
    uint8_t src[] = { 
        0xe0, 0x3, 0x1f, 0xf8, 0xc0, 0x7, 0x3e, 0xf0, 0x81, 0xf, 0x7c, 0xe0, 0x3, 0x1f, 0xf8, 0xc0, 0x7, 0x3e, 0xf0, 0x81, 0xf, 0x7c, 0xad
    };
    UnpackChannels(src, dst);
    for (unsigned ch=0; ch<16; ++ch)
        printf("ch%02u=%u ", ch, dst[ch]);
    printf("\n");
    return 0;
}
ch00=992 ch01=992 ch02=992 ch03=992 ch04=992 ch05=992 ch06=992 ch07=992 ch08=992 ch09=992 ch10=992 ch11=992 ch12=992 ch13=992 ch14=992 ch15=992 

thank you very much, I understand that this is not a code school) thanks to you, I at least understood a little bit about CRSF protocol and how it works.

CapnBry commented 5 months ago

I've opened the Discussions section of this repository so stuff like this should go in Q&A moving forward!