Dzień dobry,
Z problemem borykam się już długi czas, ale utknąłem i obawiam się że moja wiedza jest po prostu niewystarczająca, by wszystko zrozumieć - szukam pomocy.
Usiłuję skomunikować ze sobą nadajnik Silicon Labs
Si4010 oraz wariometr Flymaster GPS SD
(jego odbiornik to Si4355
) za pomocą sygnału radiowego. Chcę wysłać odczyt temperatury z zewnętrznego czujnika (termometru zamontowanego na szycie powłoki balonu na ogrzane powietrze). Urządzenie nie pokazuje sygnału nadajnika w swoim interfejsie najprawdopodobniej z powodu niepoprawnego sygnału.
Sygnał, który muszę wysłać został mi opisany tak:
[PREAMBLE][PREAMBLE][PACK_ID][DATA][CRC]
4 bytes for preamble + 2 for syncword + 2 for datatype and ID + 2 data + 1 for CRC
(w pierwszej linijce producent najwyraźniej zapomniał wpisać syncword)
Wydaje mi się, że 80% tego sygnału mam przygotowane poprawnie, ale nie rozumiem funkcji generującej sumę kontrolną CRC.
Od producenta wariometru dostałem skrawki kodu które mają mi pomóc:
RF CODE
Kod nadajnika jest dostępny na GitLab - plik keyfob_demo_2_main.c. Jest to zmodyfikowany przykład kodu nadajnika wysyłającego numer naciśniętego przycisku.
A więc po kolei to, co udało mi się zrobić na podstawie wskazań z RF CODE:
PREAMBLE = 0xAA
4 bajty PREAMBLE = 0xAAAA 0xAAAA
SYNCWORD = 0xD42D
PACKID = 0x1FFF
Wartości powyżej na podstawie przykładowego kodu od producenta
—
void FmInvertEndian(UINT16 *pwLittleEndian)
{
UINT8 hold;
UINT8 *ptr;
ptr = (UINT8*) pwLittleEndian;
hold = ptr[1];
ptr[1] = ptr[0];
ptr[0] = hold;
}
#define RF_Preamble 0xAAAA
#define RF_SyncroWord 0xD42D
// i16PacketType - sensor type
// i16ID - serial number
// TAS packet type is 5 (0x5)
void InitRFPackage(UINT16 i16PacketType, UINT16 i16ID) // InitRFPackage(5,i16ID)
{
UINT8 *tmp;
// Set Preamble and SyncroWord
g_aRFPAcket[PREAMBLE_1] = RF_Preamble; // 0xAAAA
g_aRFPAcket[PREAMBLE_2] = RF_Preamble; // 0xAAAA
g_aRFPAcket[SYNCWORD_1] = RF_SyncroWord; // 0xD42D
g_aRFPAcket[PACK_ID] = i16PacketType & 0x7; // 0x5 & 0x7 -> 0x5
i16ID &= 0x1FFF;
FmInvertEndian(&i16ID);
tmp = (UINT8*) &i16ID;
tmp[0] >>= 3;
g_aRFPAcket[PACK_ID] |=i16ID; // 0x5 |= 0x1FFF -> 0x1FFF
}
—
DATA = 0xAAAA (przykładowa wartość temperatury, nie mam pojęcia jak zostanie odczytana w urządzeniu)
CRC - 0x00 - placeholder, bo nie wiem jak jest obliczana zarówno w przykładowym kodzie od producenta wariometru jak i w kodzie z którego korzystam
—
void FillRFPacket()
{
UINT8 i8DataIndex;
UINT16 ai16TempBuff[2]; // maximum size of array is 3 (0,1,2)
UINT8 *ptri8;
InitRFPackage(5,g_i16SerialNumber);
ptri8= (UINT8*) (g_aRFPAcket + HDRSIZE ); // co to jest HDRSIZE?
ai16TempBuff[0] = g_aRFPAcket[PACK_ID]; // = 0x1FFF
// ai16TempBuff = [0x1FFF]
for(i8DataIndex=0; i8DataIndex < g_i16BufferIndex; i8DataIndex++) // co to jest g_i16BufferIndex?
{
ai16TempBuff[1] = g_aRFBuffer[i8DataIndex];
memcpy(ptri8, (UINT8*) (ai16TempBuff+1), sizeof(UINT16) );
ptri8 += sizeof(UINT16);
*ptri8 = calculate_CRC((UINT8*) ai16TempBuff,(2*sizeof(UINT16)));
ptri8++;
}
}
UINT8 calculate_CRC(UINT8 *ptrTemp,UINT8 i8Lenght)
{
UINT8 i8CRC=0,i8;
for(i8 = 0; i8 < i8Lenght; i8++) // Last byte is CRC byte
{
i8CRC ^= ptrTemp[i8];
}
return(i8CRC);
}
---
Oraz kod odpowiadający za przygotowanie sygnału do wysłania:
—
void PutOnRFBuffer(UINT16 i16ValueToSend)
{
if(g_i16BufferIndex>RF_BUFFER_SIZE) return;
g_aRFBuffer[g_i16BufferIndex]=i16ValueToSend;
g_i16BufferIndex++;
}
// Prepare data to be sent
#define THERMISTOR_ID_MASK 0xC000 // thermistor data id
void PrepareToSend(UINT16 i16DataType, UINT16 i16DataValue)
{
// Mask Data
i16DataValue &= 0x3FFF; // clean mask
i16DataValue |= THERMISTOR_ID_MASK;
PutOnRFBuffer(i16DataValue);
}
—
Podsumowując, z tego co rozumiem ramka sygnału powinna wyglądać tak:
0xAAAA 0xAAAA 0xD42D 0x1FFF 0xAAAA 0x00
Przekształcając to na kod, który napisałem przerabiając przykładowy program od Silicon Labs:
—
void vPacketAssemble (void)
{
BYTE i;
pbFrameHead = abFrame ;
bFrameSize = bFrameSize_c;
for (i=0;i<bPreambleSize_c;i++) // bPreambleSize_c = 4
{
abFrame[i] = bPreamble;
}
abFrame[bFrameSize_c - 9] = bSync1_c; // 0x2D
abFrame[bFrameSize_c - 8] = bSync2_c; // 0xD4
abFrame[bFrameSize_c - 7] = 0x5; // TAS packet type
abFrame[bFrameSize_c - 6] = 0x1F; // example ID
abFrame[bFrameSize_c - 5] = 0xFF; // example ID
abFrame[bFrameSize_c - 4] = 0xAA; // example data
abFrame[bFrameSize_c - 3] = 0xAA; // example data
abFrame[bFrameSize_c - 2] = 0; //CRC, see function vCalculateCrc below
abFrame[bFrameSize_c - 1] = 0; //CRC, see function vCalculateCrc below
vCalculateCrc();
return;
}
//--------------------------------------------------------------
//Calculate CRC and write in the frame buffer
//Bit pattern used (1)1000 0000 0000 0101, X16+X15+X2+1
void vCalculateCrc(void)
{
BYTE i,j;
WORD wCrc;
wCrc = 0xffff;
for(j = bPayloadStartIndex_c;j<bPayloadStartIndex_c + bPayloadSize_c;j++)
{
wCrc = wCrc ^ ((WORD)abFrame[j]<<8);
for (i = 8; i != 0; i--)
{
if (wCrc & 0x8000)
{
wCrc = (wCrc << 1) ^ 0x8005;
}
else
{
wCrc <<= 1;
}
}
}
//-----------------------------------------------------------------
//Write CRC in frame
abFrame[bFrameSize_c - 2] = ((BYTE*)&wCrc)[0];
abFrame[bFrameSize_c - 1] = ((BYTE*)&wCrc)[1];
return;
}
---
Wysyłam to, ale niestety żadne wykryte urządzenie nie pojawia w odbiorniku. Nie bardzo wiem co może być przyczyną.
PS. Jestem również w stanie "odpłacić się" finansowo lub lotem balonem dla jednej osoby w Krakowie za dokończenie rozwiązania i poprawne skomunikowanie urządzeń. Mieszkam w Krakowie, posiadam devkit Silicon Labs oraz wariometr.