Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Przenoszenie pola struktury jako argument funkcji

Ostatnio zmodyfikowano 2017-02-05 19:42
Autor Wiadomość
kamil2234
Temat założony przez niniejszego użytkownika
Przenoszenie pola struktury jako argument funkcji
» 2017-02-02 19:17:22
Obecnie mam bardzo nieelegancki kod do wyliczania  wartości offsetof dla każdego pola w strukturze. Za każdym razem kiedy dodaje nowe pole do struktury muszę definiować dodatkowo offsetof co jest trudne w utrzymaniu kodu.

C/C++
#include <Wire.h>
#include <I2C_EEPROM.h>
AT24C32 < 0x57 > eep; //for RTC3231
#define offsetof(s,m) (size_t)&(((s *)NULL)->m)

struct MySetingsTab {
    char struct_start[ 10 ];
    char wifi_ssid[ 255 ];
    char wifi_password[ 255 ];
    int svrport;
    int dhcp;
    int ip_0;
    int ip_1;
    int ip_2;
    int ip_3;
    int nm_0;
    int nm_1;
    int nm_2;
    int nm_3;
    int gw_0;
    int gw_1;
    int gw_2;
    int gw_3;
    int dns_p0;
    int dns_p1;
    int dns_p2;
    int dns_p3;
    int dns_s0;
    int dns_s1;
    int dns_s2;
    int dns_s3;
    char system_login[ 255 ];
    char system_password[ 255 ];
    // setings  for sleep mode option - work if this option is active
    int active_time;
    int sleep_time;
    // setings for remote raporting sensor values
    int remote_raporting;
    int frequency_sec;
    char remote_url[ 255 ];
   
   
    char struct_end[ 10 ];
   
} mysetingstab, setingsfromdb;

size_t offset_struct_start = offsetof( MySetingsTab, struct_start );
size_t offset_wifi_ssid = offsetof( MySetingsTab, wifi_ssid );
size_t offset_wifi_password = offsetof( MySetingsTab, wifi_password );
size_t offset_svrport = offsetof( MySetingsTab, svrport );
size_t offset_dhcp = offsetof( MySetingsTab, dhcp );
size_t offset_ip_0 = offsetof( MySetingsTab, ip_0 );
size_t offset_ip_1 = offsetof( MySetingsTab, ip_1 );
size_t offset_ip_2 = offsetof( MySetingsTab, ip_2 );
size_t offset_ip_3 = offsetof( MySetingsTab, ip_3 );
size_t offset_nm_0 = offsetof( MySetingsTab, nm_0 );
size_t offset_nm_1 = offsetof( MySetingsTab, nm_1 );
size_t offset_nm_2 = offsetof( MySetingsTab, nm_2 );
size_t offset_nm_3 = offsetof( MySetingsTab, nm_3 );
size_t offset_gw_0 = offsetof( MySetingsTab, gw_0 );
size_t offset_gw_1 = offsetof( MySetingsTab, gw_1 );
size_t offset_gw_2 = offsetof( MySetingsTab, gw_2 );
size_t offset_gw_3 = offsetof( MySetingsTab, gw_3 );
size_t offset_dns_p0 = offsetof( MySetingsTab, dns_p0 );
size_t offset_dns_p1 = offsetof( MySetingsTab, dns_p1 );
size_t offset_dns_p2 = offsetof( MySetingsTab, dns_p2 );
size_t offset_dns_p3 = offsetof( MySetingsTab, dns_p3 );
size_t offset_dns_s0 = offsetof( MySetingsTab, dns_s0 );
size_t offset_dns_s1 = offsetof( MySetingsTab, dns_s1 );
size_t offset_dns_s2 = offsetof( MySetingsTab, dns_s2 );
size_t offset_dns_s3 = offsetof( MySetingsTab, dns_s3 );
size_t offset_system_login = offsetof( MySetingsTab, system_login );
size_t offset_system_password = offsetof( MySetingsTab, system_password );
size_t offset_active_time = offsetof( MySetingsTab, active_time );
size_t offset_sleep_time = offsetof( MySetingsTab, sleep_time );
size_t offset_remote_raporting = offsetof( MySetingsTab, remote_raporting );
size_t offset_frequency_sec = offsetof( MySetingsTab, frequency_sec );
size_t offset_remote_url = offsetof( MySetingsTab, remote_url );
size_t offset_struct_end = offsetof( MySetingsTab, struct_end );


Przypadek użycia kodu jest potem taki jak poniżej.  Pozwala zapisać do pamięci eeprom we wskazane miejsce dane dotyczące tylko konkretnego pola w strukturze. Dzięki czemu mogę sobie oszczędzić ograniczoną ilość cyki zapisu. Nie zapisuję całej struktury tylko wybrane pola. Kod zapisu do eeprom bazuje na wyliczonym adresie w pamięci. 

C/C++
mysetingstab.wifi_password = "mypassword";
eep.put( offset_wifi_password, mysetingstab.wifi_password );


Chciałbym jednak zaoszczędzić sobie pracy podczas utrzymania kodu i wyliczać offsetof dynamicznie dla każdego przypadku użycia.niech jakaś inna funkcja się martwi o to jaki jest adres dla danego pola w określonej strukurze.  Potrzebuję więc napisać funkcję, która będzie działać tak ja ta poniżej. Oczywiście poniższy kod to bzdura, ale chyba obrazuje co chcę osiągnąć.  Bardzo proszę o pomoc i sugestię. 


C/C++
void save_data( mysetingstab.field ) {
   
    int offsetof = offsetof( mysetingstab.field );
   
    eep.put( offsetof, mysetingstab.field );
}

save_data( mysetingstab.wifi_password );
P-157244
darko202
» 2017-02-03 14:19:25
trudno mi się połapać z czym masz problem :(
 
dlatego zadam narzucające mi się -może głupie- pytanie :  czy myślałeś nad wykorzystaniem do rozwiązania "switch" ?
oczywiście wewnątrz poszukiwanej przez Ciebie funkcji
P-157272
kamil2234
Temat założony przez niniejszego użytkownika
» 2017-02-03 14:51:02
Problem jest w tym, że nie chcę  wyliczać adresu za każdym razem dla nowego pola, które dodam sobie do struktury. Żeby zapisać dane do pamięci eeprom trzeba wyliczyć adres komórki pamięci dla danego pola.   Zauważ, że funkcja put posiada dwa parametry, które pozwalają zapisać dane do pamięci. 

 
C/C++
eep.put( adres pami ę ci, warto ś ć );
 
Chcę więc umieść funkcję put w ramach innej funkcji.  Chciałbym aby ta funkcja posiadała tylko jeden parametr myStruct.field.   Kostrukcja mogła by wyglądać tak:

 
C/C++
void save( struktura.pole ) { // argumentem ma być użyta w wywołaniu struktura z polem
   
    int offsetof = offsetof( argument to struktura z polem ); // obliczenie adresu w pamięci
   
    eep.put( offsetof, argument to struktura z polem ); // użycie pierwotnej funkcji zapisu do eeprom
   
   
}

save( myStruct.field ); // wywołanie funkcji z polem struktury.
 

Szukam jakieś rozwiązania, które pozwoli mi osiągnąć taki efekt jw. 


Korzystam z tej biblioteki. https://github.com/CombiesGit/I2C_EEPROM
P-157275
1aam2am1
» 2017-02-03 16:49:46
Dlaczego niewykorzystasz eeprom_update_block?
P-157277
mokrowski
» 2017-02-03 18:02:49
Nie wiem co i jak często robisz z pamięcią EEPROM ale może zacznij od tego że policzysz ile razy wykonujesz te operacje. Jeśli przy wyłączaniu systemu wykonywany jest zapis zmienionych ustawień, to może okazać się że ilość operacji wystarczy Ci na 20 lat... :-) Wtedy określisz czy warto kruszyć kopię. Policzyłeś to?
P-157282
kamil2234
Temat założony przez niniejszego użytkownika
» 2017-02-04 13:39:39
1aam2am1  -> Eeprom update?  Nie widziałem, że w tej bibliotece była taka funkcja. 

mokrowski -> Nie chodzi o częstotliwość zapisu tylko o szybkość zapisu i przejrzystość kodu. Nie chcę zapisywać za każdym razem całej struktury.  Wczoraj napisałem kod troszkę inaczej, ale dalej nie operuję na polach tylko całych strukturach, co prowadzi do bezsensownego marnowania pamięci.  Mimo to załączę ten kod może komuś się przyda do Arduino :)

biblioteka jest tutaj: https://github.com/CombiesGit/I2C_EEPROM

C/C++
#include <Wire.h>
#include <I2C_EEPROM.h>
AT24C32 < 0x57 > eep; //for RTC3231
#define offsetof(s,m) (size_t)&(((s *)NULL)->m)

struct schema {
    char f_varchar[ 64 ];
    int f_int;
    float f_float;
    double f_double;
    int f_id;
};

int rec_id = 0;

void EraseEpprom() {
   
    if( eep.ready() ) {
       
        Serial.println( "Epprom ready..." );
        Serial.println( "Erase epprom..." );
        //erase epprom
        for( int i = 0; i < eep.length(); i++ ) {
            uint16_t an = i;
            int vb = 0;
            eep.put( an, vb );
            // Serial.print("mem erase address: ");
            //Serial.println(i);
            delay( 10 );
        } // end for
        Serial.println( "DONE -> WAIT TIME  1 sek" );
        delay( 1000 );
    }
    else {
        Serial.println( "EraseEpprom -> conection problem" );
    }
}

schema InitEepromValue( int rec_id ) {
   
    // Serial.print("rec_id in InitEepromValue is: ");
    // Serial.println(rec_id);
   
   
    schema instance;
    instance.f_id = rec_id; // set record id for eeprom
    strcpy( instance.f_varchar, "" ); // set empty value
    return( instance ); // return structure
}

schema GetFormDB( struct schema instance ) {
    schema odbior;
    strcpy( odbior.f_varchar, "er" );
    odbior.f_id = 0;
    odbior.f_float = 0.0;
    odbior.f_double = 0.0001;
   
    size_t offset = sizeof( schema );
   
    offset =( offset * instance.f_id ) - offset;
    // Serial.println("offset is:");
    // Serial.println(offset);
   
    if( eep.ready() ) {
       
       
        // Serial.println("Get form DB ");
        eep.fastBlockRead( offset, & instance, sizeof( schema ) );
        delay( 2 );
       
        // Serial.println(instance.f_varchar);
        // Serial.println(instance.f_id);
       
        return( instance );
       
       
    }
    else {
        Serial.println( "GetFormDB -> conection problem" );
        return( odbior );
    } // end if
   
   
} // end function GetFormDB 







void SaveToDB( struct schema instance ) {
   
    //printf( "data save : %s\n", instance.f_varchar);
    size_t offset = sizeof( schema );
   
    offset =( offset * instance.f_id ) - offset;
    //Serial.println("offset is:");
    //Serial.println(offset);
   
   
    if( eep.ready() ) {
        // Serial.println("Set to DB ");
        eep.put( offset, instance );
        delay( 2 );
    }
    else {
        Serial.println( "InsertToDB -> conection problem" );
    } // end if
   
}


void setup() {
    Serial.begin( 9600 );
    delay( 3000 );
    Wire.begin();
    delay( 3000 );
    delay( 1000 );
   
    // def
    struct schema sample_instance;
    struct schema login_wifi = InitEepromValue( rec_id ); rec_id++;
    struct schema haslo_wifi = InitEepromValue( rec_id ); rec_id++;
    struct schema port = InitEepromValue( rec_id ); rec_id++;
    struct schema last_temp = InitEepromValue( rec_id ); rec_id++;
   
   
    // default setings
    strcpy( login_wifi.f_varchar, "admin" );
    strcpy( haslo_wifi.f_varchar, "Mojetajnehaslo" );
    port.f_int = 80;
    last_temp.f_float = 23.21;
   
    //EraseEpprom();
   
   
   
    SaveToDB( login_wifi );
   
    SaveToDB( haslo_wifi );
   
    SaveToDB( last_temp );
   
    SaveToDB( port );
   
    login_wifi = GetFormDB( login_wifi );
    haslo_wifi = GetFormDB( haslo_wifi );
    last_temp = GetFormDB( last_temp );
    port = GetFormDB( port );
   
   
    Serial.print( "haslo_wifi.f_varchar to: " );
    Serial.println( haslo_wifi.f_varchar );
   
    Serial.print( "login_wifi.f_varchar to: " );
    Serial.println( login_wifi.f_varchar );
   
   
    Serial.print( "last_temp float to: " );
    Serial.println( last_temp.f_float );
   
   
    Serial.print( "port.int to: " );
    Serial.println( port.f_int );
   
   
} // end setup

void loop() {
   
   
} // end loop
 
P-157323
Gibas11
» 2017-02-04 14:04:24
Nie jestem pewny czy dobrze rozumiem, ale chodzi Ci po prostu o różnicę między adresem jakiegoś pola a początkiem obiektu/struktury? Jeśli tak to nie wystarczy ten kod?
C/C++
long offset_of( char * object, char * field ) {
    return field - object;
}
P-157324
kamil2234
Temat założony przez niniejszego użytkownika
» 2017-02-04 18:24:12
Jak wywołać tą funkcję? Co się wyliczy jako wartość różnicy? Nie kumam tego.
P-157340
« 1 » 2
  Strona 1 z 2 Następna strona