Funktionsargumente mit Pointern



  • Moin,

    ich lese meinen Stromzähler mit einem esp8266 per Infrarot aus und möchte die Werte per mqtt im LAN veröffentlichen. Dazu habe ich folgendes zusammen geklöppelt:

    https://github.com/rollercontainer/sml2mqtt

    Die binären SML Daten stehen in einem unsigned char array. Um Sie zu decodieren, möchte ich gerne diese smllib benutzen: https://github.com/tobiasjeske/SMLlib

    Die Funktion, die ich aufrufen möchte sieht so aus:

    uint8_t sml_transport_parse_message(const unsigned char* smlBinary, uint32_t* offset, SML_Message* message)
    

    und steht hier: https://github.com/tobiasjeske/SMLlib/blob/master/src/smllib_parse.c#L107

    dafür habe ich:

    unsigned char smlBinary[smlIndex];
      uint32_t offset = 0;
      SML_Message decodedMessage;
    

    Meine Interpretation sieht so aus:

    int result = sml_transport_parse_message(smlBinary, &offset, &decodedMessage);
    

    führt aber zu undefined reference.
    Lege ich einen Pointer auf smlBinary an und übergebe den:

    const unsigned char* ptrSmlBinary = smlBinary; // which is &smlBinary[0]
      int result = sml_transport_parse_message(*ptrSmlBinary, &offset, &decodedMessage);
    

    erhalte ich:

    error: invalid conversion from 'unsigned char' to 'const unsigned char*'
    

    Ich komme aus der PHP Welt und schnalle das einfach nicht. Kann mich jemand erhellen?



  • Dein erster Versuch ist (wohl) schon richtig. Die Fehlermeldung "undefined reference" kommt vom Linker: du mußt die SMLib noch mitlinken lassen.

    Welche IDE verwendest du?



  • Die Arduino IDE. Die lib mit allen .h und .c Dateien liegt im selben Ordner und ist per include "smllib_parse.h" eingebunden. Wird auch übersetzt, so wie ich das sehe.



  • Wie lautet die koplette Fehlermeldung (copy&paste)?
    Du mischt also c und c++ - sind die Funktionen mit extern "C" deklariert?



  • No, there is no "extern C". How do I identify the border between c and c++?

    Here is the full code. Funtion call is at the end. I'll state the error code this evening.

    /*
       Program for isolating and publishing smartmeter sml messages to a mqtt broker by using a esp8266.
       Version 1 for nodeMCU or Adafruit Huzzah boards
    
       @author Tim Abels <rollercontainer@googlemail.com>
       @see The GNU Public License (GPL)
    
       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.
    
       This program is distributed in the hope that it will be useful, but
       WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
       for more details.
    
       You should have received a copy of the GNU General Public License along
       with this program; if not, see <http://www.gnu.org/licenses/>.
    */
    
    #define RX_PIN 4 // for NodeMCU: GPIO4 = D1 
    #define TX_PIN 5 // for NodeMCU: GPIO5 = D2
    #define MQTT_MAX_PACKET_SIZE 1024 // Maximum packet size (mqtt max = 4kB)
    #define MQTT_KEEPALIVE 120 // keepAlive interval in Seconds
    
    #include <ESP8266WiFi.h>
    #include <ESP8266mDNS.h>
    #include <WiFiUdp.h>
    #include <ArduinoOTA.h>
    #include "smllib_parse.h"
    
    // Software serial is needed for debuging reasons.
    // esp8266 has only one real hardware serial which is connected to usb
    #include <SoftwareSerial.h> // https://github.com/plerup/espsoftwareserial
    #include <PubSubClient.h>   // https://github.com/knolleary/pubsubclient/blob/master/examples/mqtt_esp8266/mqtt_esp8266.ino
    
    #include "Config.h" // make your own config file or remove this line and use the following lines
    //const char* clientId = "smartmeter";
    //const char* mqtt_server = "192.168.x.y";
    //const char* ssid = "PUT-YOUR-SSID-HERE";
    //const char* password = "PUT-YOUR-WIFI-PASSWORD-HERE";
    //IPAddress ip(192, 168, x, y); // Static IP
    //IPAddress dns(192, 168, x, y); // most likely your router
    //IPAddress gateway(192, 168, x, y); // most likely your router
    //IPAddress subnet(255, 255, 255, 0);
    
    byte inByte; // for reading from serial
    unsigned char smlBuffer[700]; // for storing the the isolated message. Mine was 280 bytes, but may vary...
    const byte startSequence[] = { 0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01 }; // see sml protocol
    const byte stopSequence[]  = { 0x1B, 0x1B, 0x1B, 0x1B, 0x1A };
    
    bool connectedToMQTT = false;
    
    int smlIndex;     // represents the actual position in smlMessage
    int startIndex;   // for counting startSequence hits
    int stopIndex;    // for counting stopSequence hits
    int stage;        // defines what to do next. 0 = searchStart, 1 = searchStop, 2 = publish message
    
    SoftwareSerial infraredHead( RX_PIN, TX_PIN, false, 256); // RX, TX, Inverse, Buffer
    WiFiClient espClient;
    PubSubClient mqttClient(espClient);
    
    void setup_wifi() {
      delay(10);
      Serial.print("Connecting to ");
      Serial.println(ssid);
      WiFi.config(ip, dns, gateway, subnet);
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    
    void mqttCallback(char* topic, byte* payload, unsigned int length) {
      // not used in this example
    }
    
    void mqttReconnect() {
      // Loop until we're reconnected
      while (!mqttClient.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (mqttClient.connect(clientId)) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          char* topic = "/energy/status";
          char* path = (char *) malloc(1 + strlen(clientId) + strlen(topic) );
          strcpy(path, clientId);
          strcat(path, topic);
          mqttClient.publish(path, "online");
          // ... and resubscribe
          //mqttClient.subscribe("smartmeter/inTopic");
        } else {
          Serial.print("failed, rc=");
          Serial.print(mqttClient.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }
    
    void setup() {
      Serial.begin(115200);
      Serial.println("\nHardware serial started");
      infraredHead.begin(9600);
      Serial.println("\nSoftware serial started");
      setup_wifi();
      mqttClient.setServer(mqtt_server, 1883);
      mqttClient.setCallback(mqttCallback);
      // --------------------------------------------------------------------- OTA
    
      // Port defaults to 8266
      // ArduinoOTA.setPort(8266);
    
      // Hostname defaults to esp8266-[ChipID]
      ArduinoOTA.setHostname(clientId);
    
      // No authentication by default
      ArduinoOTA.setPassword((const char *)"08154711");
    
      ArduinoOTA.onStart([]() {
        Serial.println("Start");
      });
      ArduinoOTA.onEnd([]() {
        Serial.println("\nEnd");
      });
      ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
      });
      ArduinoOTA.onError([](ota_error_t error) {
        Serial.printf("Error[%u]: ", error);
        if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
        else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
        else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
        else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
        else if (error == OTA_END_ERROR) Serial.println("End Failed");
      });
      ArduinoOTA.begin();
    }
    
    void loop() {
      ArduinoOTA.handle();
      if (!mqttClient.connected()) {
        mqttReconnect();
      }
      mqttClient.loop();
    
      switch (stage) {
        case 0:
          findStartSequence();
          break;
        case 1:
          findStopSequence();
          break;
        case 2:
          publishMessage();
          break;
      }
    }
    void findStartSequence() {
      while (infraredHead.available())
      {
        inByte = infraredHead.read();
        if (inByte == startSequence[startIndex])
        {
          smlBuffer[startIndex] = inByte;
          startIndex++;
          if (startIndex == sizeof(startSequence))
          {
            stage = 1;
            smlIndex = startIndex;
            startIndex = 0;
          }
        }
        else {
          startIndex = 0;
        }
      }
    }
    
    void findStopSequence() {
      while (infraredHead.available())
      {
        inByte = infraredHead.read();
        smlBuffer[smlIndex] = inByte;
        smlIndex++;
    
        if (inByte == stopSequence[stopIndex])
        {
          stopIndex++;
          if (stopIndex == sizeof(stopSequence))
          {
            stage = 2;
            stopIndex = 0;
    
            // after the stop sequence, ther are sill 3 bytes to come.
            // One for the amount of fillbytes plus two bytes for calculating CRC.
            delay(30); // wait for the 3 bytes
            for (int c = 0 ; c < 3 ; c++) {
              smlBuffer[smlIndex++] = infraredHead.read();
            }
            smlIndex--;
          }
        }
        else {
          stopIndex = 0;
        }
      }
    }
    
    void publishMessage() {
    
      int arrSize = 2 * smlIndex + 1;
      char smlBufferAsString[arrSize];
      char *myPtr = &smlBufferAsString[0]; //or just myPtr=charArr; but the former described it better.
    
      for (int i = 0; i <= smlIndex; i++) {
        snprintf(myPtr, 3, "%02x", smlBuffer[i]); //convert a byte to character string, and save 2 characters (+null) to charArr;
        myPtr += 2; //increment the pointer by two characters in charArr so that next time the null from the previous go is overwritten.
      }
    
      uint32_t offset = 0;
      SML_Message decodedMessage;
      unsigned char smlBinary[smlIndex];
      memmove(smlBinary,smlBuffer,smlIndex); // cut the sml data out of the buffer
      int result = sml_transport_parse_message(smlBinary, &offset, &decodedMessage);   
      Serial.println(result); // for debuging
    
      char* topic = "/energy/sml";
      char* path = (char *) malloc(1 + strlen(clientId) + strlen(topic) );
      strcpy(path, clientId);
      strcat(path, topic);
      mqttClient.publish(path, smlBufferAsString);
      memset(smlBuffer, 0, sizeof(smlBuffer)); // clear the buffer
      smlIndex = 0;
      stage = 0; // start over
    }
    


  • extern "C"
    {
    #include "smllib_parse.h"
    }
    

    did the trick. Compiles without errors. I will upload it this evening and report the result.

    Thx



  • Da bin ich wohl ins englische abgerutscht ^^

    Hat funktioniert. Nur leider mag die Lib meine Daten nicht und gibt nur eine 1 zurück (PARSE_ERROR) und die "Maintainer" sind keine. Hätte ja auch klappen können.

    Naja was solls, hack ich halt Holz!


Log in to reply