uso di struct extern

Buongiorno.
Ho già provato mille combinazioni ma non riesco a compilare.

Nel .ino c’è:

const struct {
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
} BINARY_INFO[3]= {
  /*  No. , Width , Height , Size , Start Address  */ 
  {1,1024,600,1228800,0},          /*     art , element 0     */
  {2,1024,600,1228800,1228800},          /*     scada , element 1     */
  {3,236,238,112336,2457600},          /*     button , element 2     */
};

Nella libreria ho messo di tutto, per esempio:

extern const struct{
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
} BINARY_INFO[];

E l’errore è:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Zero (Native USB Port)"


DMA_Pics_from_flash:13:16: error: conflicting declaration 'const<unnamed struct> BINARY_INFO [3]'

} BINARY_INFO[3]= {

               ^

In file included from gevino_tft_dislplay.h:2:0,

                from DMA_Pics_from_flash.ino:5:

gevinoTFT_RA8876.h:15:3: note: previous declaration as 'const<unnamed struct> BINARY_INFO []'

} BINARY_INFO[];
  ^~~~~~~~~~~
exit status 1
conflicting declaration 'const<unnamed struct> BINARY_INFO [3]'

Consiglio di separare un pò le cose.

  1. creare un tipo specifico per quel struct e metterlo in un suo .h usando typedef
    esempio:
    file nuova.h
#ifndef NUOVA_H
#define NUOVA_H

#define K_BINARY_LEN 3

typedef struct {
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
} T_NUOVA;
#endif

Poi nel file .ino fai include di questo nuova.h e quindi semplifichi:

#include "nuova.h"
...
const T_NUOVA BINARY_INFO[K_BINARY_LEN]= {  /*  No. , Width , Height , Size , Start Address  */
    {1,1024,600,1228800,0},             /*     art , element 0     */
    {2,1024,600,1228800,1228800},       /*     scada , element 1         */
    {3,236,238,112336,2457600},         /*     button , element 2     */
};

Nella libreria, nel file includi comunque nuova.h (che definisce cosa è T_NUOVA)
e poi prova con:

#include "nuova.h"
...
extern const T_NUOVA BINARY_INFO[K_BINARY_LEN];

se nell'esempio che ti ho messo io se togliamo const riesce a compilare:

// nuova.h
#ifndef NUOVA_H
#define NUOVA_H

#define K_BINARY_LEN 3
#define arraySize 10

typedef struct {
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
} T_NUOVA;

int GetNumber(int);

#endif

// nuova.cpp
#include "nuova.h"

extern T_NUOVA BINARY_INFO[K_BINARY_LEN];

int GetNumber(int idx)
{ int x= BINARY_INFO[idx].number;
  return(x);
}

//prova.ino
#include "nuova.h"

T_NUOVA BINARY_INFO[K_BINARY_LEN]= {  /*  No. , Width , Height , Size , Start Address  */
    {1,1024,600,1228800,0},             /*     art , element 0     */
    {2,1024,600,1228800,1228800},       /*     scada , element 1         */
    {3,236,238,112336,2457600},         /*     button , element 2     */
};

void setup()
{ Serial.begin(9600);
  Serial.println(__FILE__);
  Serial.println(BINARY_INFO[0].number);
  Serial.println(GetNumber(1));
}

void loop() { }

Prova a leggere qui: https://forum.arduino.cc/index.php?topic=659107.msg4440960#msg4440960
Pare il problema sia il C++ in cui le const devono essere in unità diversi (?!?)
Però esempio al link compila anche con const (ma usa anche PROGMEM)

Allego libreria e .ino per arduino zero SAMD

Un programma della RAIO, che prende delle foto, ne crea un unico bin e la struttura per usarlo.
Il bin si programma nel chip flash, e poi il controller fa DMA e lo visualizza.

La cosa si complice perchè la devo usare dentro a una classe.
La struttura è generata in automatico dal programma Image_Tool.exe della RAIO, ed è appartenente al progetto, per cui va messo con lo sketch e non nelle librerie.
Lo ho incluso nel .ino

la keywords code, per farla digerire, ho messo un define

#define code PROGMEM 
#include "pic.h"

E dentro a pic.h c'è

typedef struct _info
{
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
}INFO;

  /* The 'code' is KEIL C 8051 instruction, please refer to http://www.keil.com/support/man/docs/c51/c51_le_code.htm */
  /* If you do not use the 8051 microcontroller system, please remove the 'code' instruction. */

const INFO code BINARY_INFO[3]=
{
  /*  No. , Width , Height , Size , Start Address  */ 
  {1,1024,600,1228800,0},          /*     art , element 0     */
  {2,1024,600,1228800,1228800},          /*     scada , element 1     */
  {3,236,238,112336,2457600},          /*     button , element 2     */
};

Nella libreria invece ho messo:

#ifdef def_info
#define _def_info
typedef struct _info
{
  unsigned short number;
  unsigned short img_width;
  unsigned short img_height;
  unsigned long img_size;
  unsigned long start_addr;
}INFO;
#endif

class RA8876 : public Print
{
private:
public:

  extern const INFO PROGMEM BINARY_INFO[];


  int m_csPin;
  int m_resetPin;

Però lo stesso l'errore è:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Zero (Native USB Port)"

In file included from gevino_tft_dislplay.h:2:0,

                 from DMA_Pics_from_flash.ino:5:

gevinoTFT_RA8876.h:312:16: error: 'INFO' does not name a type

   extern const INFO PROGMEM BINARY_INFO[];
                ^~~~
exit status 1

Error compiling for board Arduino Zero (Native USB Port).

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Se ti dice:

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

... e attivalo 'sto benedetto "verbose" (sia in compilazione che in upload) ... almeno ci sono un po' di dettagli ! :slight_smile:

Guglielmo

Questo è il Verbose, quì non me lo fa mettere che supera i caratteri.
Ma il problema è:
Come si mette extern in una struttura dentro a una classe ?

Mmmm … occhio, non vorrei che questa volta fosse un problema della sintassi usata …
… per sicurezza, fai solo una prova, cambia quella extern così:

extern const INFO BINARY_INFO[] PROGMEM;

… perché il PROGMEM l’ho sempre messo alla fine e non l’ho mai messo in mezzo … ::slight_smile:

Guglielmo

Occhio che extern viene risolto dal linker. Ciò che dichiaro extern è un simbolo non risolto per il compilatore.
PROGMEM invece è una direttiva per il compilatore e il linker. In breve con extern progmem è superfluo.

progmem deve essere presente nella dichiarazione definizione del dato.

Ora non ricordo ma anche const non serve con extern,

PS: posso provare solo con gcc nativo niente avr-gcc sono fuori sede. Nel pomeriggio provo ma senza progmem.

Ciao.

Dimenticavo, qui è spiegato bene come funziona const.

Il problema è che scompattando quei file serve modificare alcuni link perché non puntano al prossimo capitolo,

Altra cosa, in C++ const per i tipi built-in si comporta come la define e quindi extern su const ha poco senso.

Ciao.

Maurotec:
Dimenticavo, qui è spiegato bene come funziona const.

Occhio che GCC fa un po' le cose come dice lui ...
... ad esempio, normalmente, con altri compilatori, già il solo fatto di dire "const" presuppone che il dato venga memorizzato in flash (tanto è costante e non modificabile), con GCC questo NON è vero e comunque lui la mette in SRAM, salvo non si usi l'attributo PROGMEM.

Guglielmo

Maurotec:
Il problema è che scompattando quei file serve modificare alcuni link perché non puntano al prossimo capitolo,

Se metti quelle due cartelle nel library di arduino, e se hai installato la scheda SAMD
Te lo deve compilare.

con GCC questo NON è vero e comunque lui la mette in SRAM, salvo non si usi l'attributo PROGMEM.

Con AVR-GCC .
Per questo ho specificato che non posso provare con avr-gcc ma con gcc nativo poiché sono fuori sede.

@x-giorgio-x

Se metti quelle due cartelle nel library di arduino, e se hai installato la scheda SAMD
Te lo deve compilare.

Si io mi riferivo al libro sul C++ che ho linkato.
Come dicevo sono fuori sede e non ho arduino ide, board e tutto il resto, Ho solo un portatile non mio.

Ciao.

Maurotec:
Con AVR-GCC ....

... mmm ... vero, e lui NON sta usando un AVR, ma un ARM SAM D21 e l'attibuto PROGMEM dovrebbe essere semplicemente ignorato ... ::slight_smile:

Guglielmo

Premessa: non ho la soluzione.

Provo a riepilogare, dunque.
image_tool.exe genera codice C e non C++. Arduino per ARM usa la toolchain arm-none-eabi e il compilatore arm-none-eabi-g++ (che è C++).

PROGMEM è una macro che su AVR-GCC viene espansa in qualcosa come _attribute ecc, mentre su arm non so come funziona.

Tra C e C++ c'è grande differenza.

Ciao.

Il problema sembra essere il seguente:
Il file .ino viene compilato e si trasforma in file oggetto .o
La libreria GEVINO viene compilata e trasformata in file oggetto .o.

La palla passa al linker che deve risolvere un simbolo in modo che questo sia visibile.

Io non ho ancora fatto ciò, ma ho provato con 3 file C++: main.cpp, pic.h e picc.cpp.
L'include pic.h è presente in main.cpp e picc.cpp. Il file pic.h è l'originale non modificato.

Funziona senza warning.

// picc.cpp
#include "pic.h"

const INFO getInfo(int idx) {
    return BINARY_INFO[idx];

}

Ciao.

ho provato a

Maurotec:
Il problema sembra essere il seguente:

Mica ho capito, sono un harwarista io.
Quando accedi al tuo pc con ide arduino ?

Ho provato a rimuovere const e PROGMEM dappertutto, ma non riesco a compilare lo stesso.

C'é poi forse anche il problema che gli .h vengono compialati più volte, sia sa ino che dalla libreria.

Oggi pensavo, che forse sarebbe tecnicamente più corretto passare un puntatore alla struttura e non accedere ai dati come variabili globali, però la funzione di chiamata sarebbe molto più brutta.

Addesso è tft.pic(foto1, X,Y);

Dopo sarebbe tft.pic(INFO BINARY_INFO[foto1], X,Y);

Maurotec:
Il problema sembra essere il seguente:/quote]

Ho tolto const e PROGMEM da semplificare le cose, poi lo rimetto, ma lo stesso non mi compila.
C'è il problema del .h che viene compilato più volte.

Nel main:

#define pic_def

#include "pic.h"
#include "gevino_tft_io.h"
#include "gevino_tft_dislplay.h"




**Nel Pic.h**



typedef struct{
 unsigned short number;
 unsigned short img_width;
 unsigned short img_height;
 unsigned long img_size;
 unsigned long start_addr;
}INFO;
INFO BINARY_INFO[3]={
 {1,1024,600,1228800,0},          /*     art , element 0     /
 {2,1024,600,1228800,1228800},          /
    scada , element 1     */
};




**Nel gevino_tft_dislplay.h**


#ifndef pic_def
#define pic_def
//typedef struct _info
typedef struct
{
 unsigned short number;
 unsigned short img_width;
 unsigned short img_height;
 unsigned long img_size;
 unsigned long start_addr;
}INFO;
#endif

class RA8876 : public Print
{
private:
public:

//  extern const INFO PROGMEM BINARY_INFO;
 extern INFO BINARY_INFO;



**L'errore**


Arduino: 1.8.13 (Windows 10), Board: "Arduino Zero (Native USB Port)"

In file included from gevino_tft_dislplay.h:2:0,

from DMA_Pics_from_flash.ino:6:

gevinoTFT_RA8876.h:315:27: error: storage class specified for 'BINARY_INFO'

extern INFO BINARY_INFO;

^

gevinoTFT_RA8876.h:315:27: error: flexible array member 'RA8876::BINARY_INFO' not at end of 'class RA8876'

gevinoTFT_RA8876.h: In constructor 'constexpr RA8876::RA8876(RA8876&&)':

gevinoTFT_RA8876.h:315:27: error: initializer for flexible array member 'INFO RA8876::BINARY_INFO '

In file included from DMA_Pics_from_flash.ino:6:0:

gevino_tft_dislplay.h: At global scope:

gevino_tft_dislplay.h:5:44: note: synthesized method 'constexpr RA8876::RA8876(RA8876&&)' first required here

RA8876 tft = RA8876(RA8876_CS, RA8876_RESET);

^
exit status 1

Error compiling for board Arduino Zero (Native USB Port).

Allora no so da dove cominciare prima.

Mica ho capito, sono un harwarista io.
Quando accedi al tuo pc con ide arduino ?

Non posso usare arduino IDE, non ho il mio PC, sono su un portatile in prestito. Posso usare un altro IDE generico assime al compilatore generico per PC.

Chiarito questo punto, passiamo al codice su dropbox,

  1. La classe non deve accedere a variabili globali e BINARY_INFO[3] è globale.

  2. Le variabili membro di classe devono essere private, solo i metodi di classe devono essere esposti publicamente.

class RA8876 : public Print
{
private:

  // variabili membro private, Vi puoi accedere solo da dentro questa classe
  extern const INFO PROGMEM BINARY_INFO[];


  int m_csPin;
  int m_resetPin;

  int m_width;
  int m_height;
  int m_depth;
  int X_Cursor = 0;
  int Y_Cursor = 0;
//  uint8_t CharSpacing = 8;
  uint8_t p = 0;        // Previews Caracter
  bool ClearBG = 1;
    
  const FONT_INFO *FontNow;

  uint32_t m_oscClock;   // OSC clock (external crystal) frequency in kHz

  PllParams m_memPll;   // MCLK (memory) PLL parameters
  PllParams m_corePll;  // CCLK (core) PLL parameters
  PllParams m_scanPll;  // SCLK (LCD panel scan) PLL parameters

  SPISettings m_spiSettings;

  SdramInfo *m_sdramInfo;

  DisplayInfo *m_displayInfo;

  ExternalFontRomInfo m_fontRomInfo;

  uint16_t m_textColor;
  uint16_t m_BGtextColor;
  int      m_textScaleX = 1;
  int      m_textScaleY = 1;

  enum FontSource m_fontSource;
  enum FontSize   m_fontSize;
  FontFlags       m_fontFlags;

public:
  //  metodi publici accessibili da questa classe e dak esterno attraverso l'istanza di classe,

  void hardReset(void);
  void softReset(void);

  void writeCmd(uint8_t x);
  void writeData(uint8_t x);
  uint8_t readData(void);
  uint8_t readStatus(void);

  void writeReg(uint8_t reg, uint8_t x);
  void writeReg16(uint8_t reg, uint16_t x);
  uint8_t readReg(uint8_t reg);
  uint16_t readReg16(uint8_t reg);

  inline void waitWriteFifo(void) { while (readStatus() & 0x80); };
  inline void waitTaskBusy(void) { while (readStatus() & 0x08); };

  bool calcPllParams(uint32_t targetFreq, int kMax, PllParams *pll);
  bool calcClocks(void);
  void dumpClocks(void);

  bool initPLL(void);
  bool initMemory(SdramInfo *info);
  bool initDisplay(void);

  // Font utils
  uint8_t internalFontEncoding(enum FontEncoding enc);

  // Text/graphics mode
  void setTextMode(void);
  void setGraphicsMode(void);

Se alcuni metodi sono impiagati solo all'interno della classe questi devono essere private, al massimo protect ma solo se erediti questa classe.

Normlmente si desidera creare la libreria per scriverla una volta ed usarla tante volte senza ricompilarla,ù
L'immagine che vuoi visualizzare invece ti serve poterla cambiare quando modifichi il .ino,

  1. La libreria deve vedere questo array e il contenuto di questo può variare in base a quale immaggine vuoi impiegare con la libreria in modo da potere da cambiare immagine per ogni sketch. Questa però è una mia deduzione e mi devi dare conferma.

Secondo me dovresti creare il costruttore di casse con parametri in modo da passargli l'array.

Domani vedo di sistemare qualcosa scrivendo delle classi ristrette aderenti alle tue.

Domanda per lavorare il DMA richiede che l'array sia [const/i] ?
Ciao.

Maurotec:
Domanda per lavorare il DMA richiede che l'array sia [const/i] ?
[/quote]
Quando tornerai al tuo PC ? Sarebbe più facile se compilassi con l'IDE Arduino.
Le immagini sono in un chip Flash saldato sul controller. La prima volta le copio dalla SD al chip flash, ci mette molti minuti. Poi con il comando DMA se le legge il controller e le visualizza in decimi di secondo.
Si, ogni progetto ha immagini diverse, o potrebbe averle, per cui un pic.h dedicato al progetto.
pubblic o provate, credo sia solo un problema etico, non influisce sul funzionamento.
Come ti dicevo prima.
Se riesco a leggere i dati come variabili pubbliche mi piace di più come appare la funzione.
tft.pic(foto1, X,Y);
Se dovessi passargli un puntatore alla struttura la funzione sarebbe
tft.pic(INFO BINARY_INFO[foto1], X,Y);
Che mi piace meno, ma se non c'è alternativa....

Maurotec:
Ciao.

L'ho fatto andare passandogli il puntatore alla struttura.
Mi hanno detto che forse nella classe non è possibile usare le variabili globali.

tft.pic(&BINARY_INFO[button], 0,0);

void pic ( INFO* myInfo, uint32_t X1, uint32_t Y1);

Poi farò una macro che semplifica la chiamata alla funzione.

#define tft.pic2(a) tft.pic(&BINARY_INFO[a])