Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By ErVito
#87857 Hi folks,

I've written an example sketch which it's thought for both Arduino (with Ethernet shield) and ESP8266.
It compiles fine for both targets and executes fine on Arduino but on ESP8266 causes an Exception 9.
The sketch implements a simple server which waits to receive some messages via UDP and it should parse them properly writing in console if the message is an AckMessage, a NackMessage, a DataMessage or something else.
Once decoded the exception it seems that the method which causes the crash is the type() one of my class GenericMessage (its the parent one of the others and it's abstract).
That method is a getter which returns the type ID of the message (that is represented by an uint32_t attribute).
All attributes of the classes have been defined as uint32_t just to avoid some alignment problems but probably it isn't enough....

This is the exception decoded:
Code: Select allException 9: LoadStoreAlignmentCause: Load or store to an unaligned address
PC: 0x4020514c: GenericMessage::type() at /home/ervito/Arduino/libraries/EasyMessages/utility/GenericMessage.cpp line 13
EXCVADDR: 0x3ffef91d

Decoding stack results
0x4020126e: loop() at /home/ervito/Arduino/EasyMessagesServer/EasyMessagesServer.ino line 114
0x4010017c: ets_post(uint8, ETSSignal, ETSParam) at /home/ervito/.arduino15/packages/esp8266/hardware/esp8266/2.7.2/cores/esp8266/core_esp8266_main.cpp line 177
0x40203634: loop_wrapper() at /home/ervito/.arduino15/packages/esp8266/hardware/esp8266/2.7.2/cores/esp8266/core_esp8266_main.cpp line 197


Ant this is my example sketch:
Code: Select all#include <EasyMessages.h>

/**/
#define ENABLE_WIFI         /**/
/**
#define DEBUG_DISABLED        /* Remember to disable debug with Arduino UNO.   */
                              /* Put this define before include SerialDebug.h. */
#include <SerialDebug.h>

#ifdef ENABLE_WIFI
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

/* WIFI CONSTANTS DECLARATIONS */
const char *WIFI_SSID = "";
const char *WIFI_PWD  = "";

/* WiFi-specific variables. */
WiFiUDP dataChannel;
#else
#include <Ethernet.h>
#include <EthernetUdp.h>

/* Ethernet-specific variables. */
byte        macAddr[] = { 0x90, 0xA2, 0xDA, 0x0F, 0xAE, 0xF3 };
EthernetUDP dataChannel;
#endif

const uint16_t LOCAL_PORT  = 12345;
const uint16_t TIMEOUT     = 10000;

char    message[DATA_MESSAGE_SIZE];
uint8_t receivedBytes;

void setup() {

  Serial.begin(115200);
  Serial.println("\n");
  Serial.println("EasyMessages server example\n");
 
  Serial.println("ID | Message        | Size");
  Serial.println("==========================");
  printID(MessageTypeAck::instance()->id());
  Serial.print(" | AckMessage     | ");
  Serial.println(ACK_MESSAGE_SIZE);
  printID(MessageTypeData::instance()->id());
  Serial.print(" | DataMessage    | ");
  Serial.println(DATA_MESSAGE_SIZE);
  Serial.print(" - | GenericMessage | ");
  Serial.println(GENERIC_MESSAGE_SIZE);
  printID(MessageTypeNack::instance()->id());
  Serial.print(" | NackMessage    | ");
  Serial.println(NACK_MESSAGE_SIZE);
  Serial.println();

#ifdef ENABLE_WIFI
  uint16_t notTimeout;

  do {
    notTimeout = TIMEOUT;
    Serial.print("Connecting to wifi...");
    WiFi.begin(WIFI_SSID, WIFI_PWD);
    while (WiFi.status() != WL_CONNECTED && notTimeout) {
      delay(500);
      Serial.print(".");
      notTimeout -= 500;
    }
    if (! notTimeout)
      Serial.println("timeout.");
  } while (! notTimeout);
#else
  Serial.print("Initializing ethernet...");
  if (Ethernet.begin(macAddr) == 0) {
    Serial.println("failed.");
    while(1);
  }
#endif
  Serial.println("done."); 

  Serial.print("Initializing channel...");
  if (!dataChannel.begin(LOCAL_PORT)) {
    Serial.println("failed.");
    while(1);
  }
  Serial.println("done.");
  Serial.print("IP: ");
#ifdef ENABLE_WIFI
  Serial.println(WiFi.localIP());
#else
  Serial.println(Ethernet.localIP());
#endif

  debugSetLevel(DEBUG_LEVEL_INFO);
}

void loop() {
  delay(500);

  if ((uint8_t)dataChannel.parsePacket() >= GENERIC_MESSAGE_SIZE) {

    dataChannel.read(message, GENERIC_MESSAGE_SIZE);

    if (((GenericMessage*)message)->type() == MessageTypeAck::instance()->id())
      Serial.println("Received ACK message");
   
    if (((GenericMessage*)message)->type() == MessageTypeData::instance()->id()) {

      while((uint8_t)dataChannel.available() < DATA_MESSAGE_SIZE-GENERIC_MESSAGE_SIZE);
     
      for (; receivedBytes < DATA_MESSAGE_SIZE; receivedBytes++)
        message[receivedBytes] = dataChannel.read();

      Serial.println("Received data message");
    }
   
    if (((GenericMessage*)message)->type() == MessageTypeNack::instance()->id())
      Serial.println("Received NACK message");
  }
}

void printID(uint16_t id) {
  if (id < 10)
    Serial.print("0");
  Serial.print(id);
}


I've already tested the type() method writing a sketch which instantiates some messages (both on the stack and on the heap) and invokes the method on the objects and it tries to cast a message* to a GenericMessage* and it executes fine.
Once done some tests I suppose that the problem is in the way that the received bytes are stored and then the cast to GenericMessage* breaks all but it's my guess....
Any help would be really appreciated.
Thank you in advance for your attention and collaboration.

Best regards
Marco
User avatar
By pangolin
#87873 Given that the failing code seems to be in that library: /home/ervito/Arduino/libraries/EasyMessages/utility/GenericMessage.cpp line 13
EXCVADDR: 0x3ffef91d

this is difficult to answer and impossible to try to run+duplicate problem without seeing EasyMessages.h - What is it? Your own code or a library? If a lib, where from?
User avatar
By ErVito
#87876 Hi pangolin,

thanks for your answer.
EasyMessages is my wip library that includes some kind of messages as GenericMessage and others.
The headers are:

EasyMessages.h
Code: Select all#ifndef EASY_MESSAGES_H
#define EASY_MESSAGES_H

#include "utility/AckMessage.h"
#include "utility/DataMessage.h"
#include "utility/GenericMessage.h"
#include "utility/MessageHandler.h"
#include "utility/MessageTypeAck.h"
#include "utility/MessageTypeData.h"
#include "utility/MessageTypeNack.h"
#include "utility/MessageTypes.h"
#include "utility/NackMessage.h"

#endif /* EASY_MESSAGES_H */


GenericMessages.h
Code: Select all#ifndef GENERIC_MESSAGE_H
#define GENERIC_MESSAGE_H

#include <stdint.h>

#define GENERIC_MESSAGE_SIZE sizeof(GenericMessage)

class GenericMessage {

    /* ATTRIBUTES */
    protected:
        GenericMessage(uint32_t timestamp);
        uint32_t       _timestamp;
        uint32_t       _type;

    public:

    /* FUNCTIONS */
    public:
        uint32_t        timestamp();
        uint32_t        type();
};

#endif /* GENERIC_MESSAGE_H */


And GenericMessages.cpp is
Code: Select all#include "GenericMessage.h"

GenericMessage::GenericMessage(uint32_t timestamp) {
    _timestamp = timestamp;
}

uint32_t GenericMessage::timestamp() {
    return this->_timestamp;
}

uint32_t GenericMessage::type() {
    return this->_type;
}


Thank you in advance for your collaboration.

Best regards
Marco
User avatar
By ErVito
#87885 Hi guys,

maybe I've solved my problem.
Looking for Exception 9 caused by a cast I've found here (https://arduino.stackexchange.com/questions/67442/nodemcu-1-0-exception-9-fatal-exception-9loadstorealignmentcause) that the cause is just the way I've defined the array in which I store the received bytes (say they are N).
By default I assume that the ESP allocates N bytes padded by N*3 bytes to make them aligned to memory words of size 4 bytes.
Then when the memory has been casted to a GenericMessage*, the ESP throws the exception because the memory has been padded.
So the solution is to prevent that the memory would be padded and to make this can be added the tag __attribute__((aligned(4)) just after the type in the buffer declaration.
Code: Select allbyte __attribute__((aligned(4))) buffer[N];

In this way the N bytes should be allocated sequentially (with the plus that neither one byte of memory is lost by padding).
Is my analysis correct?

Best regards
Marco