eddy_em: (Default)
[personal profile] eddy_em
[profile] sergepl был так любезен, что прислал мне данную железяку, за что ему grand mercy!!!
Документация у этой железяки весьма скудная: куча описания того, как его подключить к дворникам (странно было бы видеть на крыше легковушки такую "дуру") или просто к релюхе, которая кричит "ахтунг" при начале дождя или ливня (можно переключателями настроить пороговые уровни). Но вот выдача данных по последовательному порту совсем уж малодокументирована. В основном мануале сказано, что, мол, читай вспомогательный. Во вспомогательном немного написано, а что до протокола, мол, читай файлик RG-11_12.ser (в котором в непонятной форме тупо описана структура данных и битовые поля, вообще без пояснений, что какое поле знает, мол, сам по названию поймешь).

Первые попытки подключиться к датчику окончились неудачей: валилась всякая откровенная дрянь. В мануале все было четко: судя по картинке, на выходе МК стоит обычный биполярный транзистор-повторитель, подтягивающий шину к +5В, когда МК выдает высокий уровень. И что-то сразу я не подумал посмотреть на осциллографе, как выглядит разделитель между пакетами (оказалось, что там был низкий уровень, но это было позже). Нагуглил, что, оказывается, сигнал-то там инвертированный (а в документации про это — ни слова)! ОК, смонтировал на макетке, используя мосфет, которым я включал питание для ИК-датчика.
Стендик

И таки пошли нормальные данные!!!
ОК, набросал код:
#include <stdio.h>
#include <usefull_macros.h>

typedef struct{
    uint8_t PeakRS;
    uint8_t SPeakRS;
    uint8_t RainAD8;
    uint8_t LRA;
    uint8_t TransRat;
    uint8_t AmbLNoise;
    uint8_t RGBits;
    uint8_t SlowRegIngex;
    uint8_t SlowRegValue;
} rg11;

typedef struct{
    uint8_t RevLevel;     // 12
    uint8_t EmLevel;      // 30..80
    uint8_t RecEmStr;     // 60..66
    uint8_t ABLevel;      // 10
    uint8_t TmprtrF;      // 70..100
    uint8_t PUGain;       // 34..39
    uint8_t ClearTR;      // 60..170
    uint8_t AmbLight;
    uint8_t Bucket;
    uint8_t Barrel;
    uint8_t RGConfig;
    uint8_t DwellT;
    uint8_t SinceRn;
    uint8_t MonoStb;
    uint8_t LightAD;      // 120..136
    uint8_t RainThr;
} slowregs;

// RGBits values:
#define PkOverThr   (1<<0)
#define Raining     (1<<1)
#define Out1On      (1<<2)
#define HtrOn       (1<<3)
#define IsDark      (1<<4)
#define Cndnstn     (1<<5)
#define Freeze      (1<<6)
#define Storm       (1<<7)

static const char* rgbitnames[8] = {
    "PkOverThr",
    "Raining",
    "Out1On",
    "HtrOn",
    "IsDark",
    "Cndnstn",
    "Freeze",
    "Storm"
};

static const char *slowregnames[16] = {
    "RevLevel",
    "EmLevel",
    "RecEmStr",
    "ABLevel",
    "TmprtrF",
    "PUGain",
    "ClearTR",
    "AmbLight",
    "Bucket",
    "Barrel",
    "RGConfig",
    "DwellT",
    "SinceRn",
    "MonoStb",
    "LightAD",
    "RainThr",
};

// minimal packet length (without slow registers)
#define REGMINLEN   (14)
// standard packet length
#define REGLEN      (18)
#define BUFLEN      (32)

static int getv(char s, uint8_t *v){
    if(s >= '0' && s <= '9'){
        *v = s - '0';
        return 1;
    }else if(s >= 'a' && s <= 'f'){
        *v = 10 + s - 'a';
        return 1;
    }
    return 0;
}

static int encodepacket(const char *buf, int len){
    uint8_t databuf[REGLEN/2] = {0};
    static slowregs slow = {0};
    if(len != REGMINLEN && len != REGLEN) return 0;
    for(int i = 0; i < len; ++i){
        int l = i&1; // low part
        int idx = i/2; // data index
        uint8_t v;
        if(!getv(buf[i], &v)) return 0;
        if(l) databuf[idx] |= v;
        else databuf[idx] |= v << 4;
    }
    rg11 r = *((rg11*)databuf);
    printf("PeakRS=%d\n", r.PeakRS);        // 0..5
    printf("SPeakRS=%d\n", r.SPeakRS);      // 0..5
    printf("RainAD8=%d\n", r.RainAD8);      // 64..192
    printf("LRA=%d\n", r.LRA);              // ?
    printf("TransRat=%d\n", r.TransRat);    // 60..170
    printf("AmbLNoise=%d\n", r.AmbLNoise);  // ?
    if(r.RGBits){
        for(int i = 0; i < 8; ++i){
            if(r.RGBits & 1<<i) printf("%s=1\n", rgbitnames[i]);
        }
    }
    uint8_t *s = (uint8_t*) &slow;
    if(len == REGLEN){
        if(r.SlowRegIngex < 16){
            s[r.SlowRegIngex] = r.SlowRegValue;
        }
    }
    for(int i = 0; i < 16; ++i){
        printf("%s=%u\n", slowregnames[i], s[i]);
    }
    printf("\n\n");
    return 1;
}

static int getpacket(TTY_descr *d){
    static int startpacket = 0, buflen = 0;
    static char strbuf[BUFLEN];
    int l = read_tty(d);
    if(l < 1) return 0;
    char s = d->buf[0];
    if(s == 's'){
        startpacket = 1;
        if(buflen){
            l = encodepacket(strbuf, buflen);
            buflen = 0;
            return l;
        }
    }else{
        startpacket = 0;
        strbuf[buflen++] = s;
        if(buflen >= BUFLEN){
            WARNX("Buffer overfull");
            buflen = 0;
        }
    }
    return 0;
}

int main(){
    TTY_descr *x = new_tty("/dev/ttyUSB0", 1200, 1);
    if(!x) return 1;
    x = tty_open(x, 1);
    if(!x) return 2;
    double t0 = dtime();
    while(dtime() - t0 < 10.){
        if(getpacket(x)) t0 = dtime();
    }
    close_tty(&x);
    return 0;
}

И на выходе стал получать нечто вроде
PeakRS=0
SPeakRS=0
RainAD8=112
LRA=122
TransRat=148
AmbLNoise=0
Raining=1
IsDark=1
Storm=1
RevLevel=14
EmLevel=38
RecEmStr=65
ABLevel=10
TmprtrF=85
PUGain=36
ClearTR=143
AmbLight=0
Bucket=12
Barrel=7
RGConfig=0
DwellT=5
SinceRn=0
MonoStb=15
LightAD=127
RainThr=12

Остается лишь разобраться, что там придумали авторы, т.к. их волшебный файлик 'RG-11_12.ser' вообще ни хрена никакой информации не содержит, кроме грубого описания битовых полей некоторых регистров, да имен регистров с их порядковыми номерами!
Разве что стало понятно, что PeakRS и SPeakRS отражают информацию о "каплях", LRA - счетчик от последнего детектирования "дождя", а остальное — да хрен бы и знал!.. Но, по крайней мере, уже с этой информацией можно как-то жить.
Гугол насчет значения полей датчика ничего не подсказал. Народ обычно использует лишь его релюшку, которая срабатывает, в зависимости от настроек переключателями на плате. Но мы же идем другим путем! И путь этот оказался вполне себе правильным. В общем, следующей стадией испытаний будет подключить провода, загерметизировать датчик обратно, да провести испытания в тазике. Жена предложила множество вариантов: от покапать пипеткой и побрызгать из пульверизатора до "обоссать" ☺
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

May 2025

S M T W T F S
    123
45678910
11121314151617
1819202122 2324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 23rd, 2025 11:23 am
Powered by Dreamwidth Studios