Други, как в конструктор передать PROGMEM константу?

Фермер
Offline
Зарегистрирован: 22.01.2020

Так – нет эффекта:

class A
{
public:
       const PROGMEM char* text;

};

A a{"Hello World!"};

 

Так – ошибка, что нельзя так делать:

A a{PSTR("Hello World!")};

Так – не хочу, ибо нужно именно в конструктор совать данные:

A a;
a.text = PSTR("Hello World!");

 

rkit
Offline
Зарегистрирован: 23.11.2016

В конструктор передать так же как в и любую другую функцию. Правда в попытках конструктора нет совсем, так что непонятно что же всё-таки хотелось.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Фермер пишет:

Так – нет эффекта:

А Какого эффекта Вы хотели получить от этой куйни?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Здравствуй жопа-новый-год.  Если что то полезное с progmem и классом то #297  eeprom_Ref.h  шаблон class pRef.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Фермер пишет:

Так – нет эффекта:

class A
{
public:
       const PROGMEM char* text;

};

A a{"Hello World!"};

 

Так – ошибка, что нельзя так делать:

A a{PSTR("Hello World!")};

Так – не хочу, ибо нужно именно в конструктор совать данные:

A a;
a.text = PSTR("Hello World!");

 

То, что у Вас написано является бредом, причём таким, который не позволяет понять, а что же Вы собственно хотели сделать. И кстати, конструктора в Вашем коде нет от слова совсем.

Попробуйте описать словами, значение которых Вы точно понимаете (не использую никаких других слов), что Вы хотите сделать.

Фермер
Offline
Зарегистрирован: 22.01.2020

ЕвгенийП пишет:

То, что у Вас написано является бредом, причём таким, который не позволяет понять, а что же Вы собственно хотели сделать. И кстати, конструктора в Вашем коде нет от слова совсем.

Попробуйте описать словами, значение которых Вы точно понимаете (не использую никаких других слов), что Вы хотите сделать.

где конкретно у меня бред? конструктор в данном примере - дефолтный.

Фермер
Offline
Зарегистрирован: 22.01.2020

mykaida пишет:

Фермер пишет:

Так – нет эффекта:

А Какого эффекта Вы хотели получить от этой куйни?

экономии RAM на 10 байт, очевидно.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Фермер затеял опасную игру, накинув на вентилятор лопату навоза.

Фермер
Offline
Зарегистрирован: 22.01.2020

rkit пишет:

В конструктор передать так же как в и любую другую функцию. Правда в попытках конструктора нет совсем, так что непонятно что же всё-таки хотелось.

У любого класса есть конструктор. Он либо написанный, либо по умолчанию. Нафига мне его писать в примитивном примере, когда можно сразу проинициализировать все свойства класса, без конструктора.

 

Фермер
Offline
Зарегистрирован: 22.01.2020

qwone пишет:

Здравствуй жопа-новый-год.  Если что то полезное с progmem и классом то #297  eeprom_Ref.h  шаблон class pRef.

 

пардон, не понял, а при чем здесь eeprom??? здесь речь про флэш память.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Здесь.

//pRef.h-----------------------------
#include <avr/pgmspace.h>
template <typename T>
class pRef {
  protected:
    const T* pointer;
    T get();
  public:
    ~pRef();
    pRef() = delete;
    pRef(const T* a);
    pRef(const pRef& other) = delete;
    pRef(pRef&& other);
    pRef& operator=(const pRef& other) = delete;
    pRef& operator=(pRef&& other);
    //
    operator T();
    pRef operator[] (const int index);
};
//pRef.cpp-----------------------------
/*uint8_t*/
template <>
uint8_t pRef<uint8_t>::get() {
  return pgm_read_byte(pointer);
}
/* int */
template <>
int pRef<int>::get() {
  return pgm_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
uint16_t pRef<uint16_t>::get() {
  return pgm_read_word(pointer);
}
/* uint32_t*/
template <>
uint32_t pRef<uint32_t>::get() {
  return pgm_read_dword(pointer);
}
/* float*/
template <>
float pRef<float>::get() {
  return pgm_read_float(pointer);
}
/*общее*/
template <typename T>
pRef<T>::~pRef() {}
template <typename T>
pRef<T>::pRef(const T* a): pointer(a) {}
template <typename T>
pRef<T>::pRef(pRef<T>&& other)
  : pointer(other.pointer) {}

template <typename T>
pRef<T>& pRef<T>::operator=(pRef<T>&& other) {
  pointer = other.pointer;
  return *this;
}
template <typename T>
pRef<T>::operator T() {
  return get();
}
template <typename T>
pRef<T> pRef<T>::operator[] (const int index) {
  return pRef<T>(pointer + index);
}
//-------------------------------------------------
using pgm_int      = pRef<int>;
using pgm_uint8_t  = pRef<uint8_t>;
using pgm_uint16_t = pRef<uint16_t>;
using pgm_uint32_t = pRef<uint32_t>;
using pgm_float    = pRef<float>;

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

 

Странные фермеры нонче пошли: спрашивают в названии темы "как в конструктор передать", а потом пишут:

Фермер пишет:

Нафига мне его писать в примитивном примере, когда можно сразу проинициализировать все свойства класса, без конструктора.

Ты эта - с внутренним Наполеоном сначала договорись, а потом раздувай щёки.

Фермер
Offline
Зарегистрирован: 22.01.2020

DIYMan пишет:

 

Странные фермеры нонче пошли: спрашивают в названии темы "как в конструктор передать", а потом пишут:

Фермер пишет:

Нафига мне его писать в примитивном примере, когда можно сразу проинициализировать все свойства класса, без конструктора.

Ты эта - с внутренним Наполеоном сначала договорись, а потом раздувай щёки.

Ну, как всегда, ушли в сторону от обсуждаемого вопроса. Объясняю: список иницилизации, фактически, вызывает default-конструтор. Т.е. конструктор есть всегда - определенный пользователем, либо default. Впредь я буду писать примеры, чтобы были поняты большинству аудитории. Прошу пардона.

Однако на мой вопрос так и нет ответа. Пока он был просто не понят (((

Фермер
Offline
Зарегистрирован: 22.01.2020

qwone пишет:

Здесь.

//pRef.h-----------------------------

Извините, я не понял. Не могли бы Вы все-таки пояснить как с помощью этого решить мою задачу?

 

JArduino
Offline
Зарегистрирован: 18.05.2019
Фермер,
А в чем конкретно проблема? У вас же вроде все правильно написано.
Только PROGMEM внутри класса лишний, ничего полезного он в нем не делает.
 
Фермер
Offline
Зарегистрирован: 22.01.2020

JArduino пишет:

Фермер,
А в чем конкретно проблема? У вас же вроде все правильно написано.
Только PROGMEM внутри класса лишний, ничего полезного он в нем не делает.

Ok, вот пример, на котором я остановился. Мне нужно, чтобы текст сидел в PROGMEM, а не в SRAM, при этом был засунут в объект в момент его инициализации.

class A
{
public:
	const char* text;
};

A a{PSTR("Hello World!")};

void setup()
{
	Serial.begin(9600);
	Serial.println(a.text);
}

void loop()
{
}

 

JArduino
Offline
Зарегистрирован: 18.05.2019

Ха, ну, во-первых, PSTR можно использовать только внутри функции, о чем компилятор вам наверняка об этом сказал.

Во-вторых, println напечатает вам чушь. Надо же сначала извлечь строку из PROGMEM.

 

Фермер
Offline
Зарегистрирован: 22.01.2020

JArduino пишет:

Во-вторых, println напечатает вам чушь. Надо же сначала извлечь строку из PROGMEM.

О, спасибо! Но как лучше это сделать?

Фермер
Offline
Зарегистрирован: 22.01.2020

sadman41 пишет:
Фермер затеял опасную игру, накинув на вентилятор лопату навоза.

Не хватает модерации этому форму. Вот на arduino.cc люди, почему-то, общаются интеллигентнее. А здесь - новичкам постоянно что-то прилетает. Причем не по дело и не в тему, а так, просто, лишь бы буркнуть что-то. 

Ну не хочется помочь человеку, ну не въехать сразу что за хрень написал человек - ну имей же мужество пройти мимо. Нафига флудить то.

 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Решение есть, но я пройду мимо. Пока.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Фермер пишет:

Не хватает модерации этому форму. Вот на arduino.cc люди, почему-то, общаются интеллигентнее

Ты мазохист, или да? Если на arduino.cc сплошь белая кость, а тебя тошнит от нас, смердов - так и шёл бы туда, что тебя останавливает? Здесь нам твои душещипательные лекции о несправедливости мироустройства - зачем?

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Спрашивай, чо непонятно

class TClass {
protected:

	PFlashString classname; // имя класса сидит в PROGMEM

public:

	TClass() { 
		classname = F("TClass");
	};

отдается элементарна

PFlashString GetClassName(void) const {	return classname;}

PFlashString описан как: 

using  PFlashString = const __FlashStringHelper *;  // указатель на строку в PROGMEM

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Фермер пишет:

sadman41 пишет:
Фермер затеял опасную игру, накинув на вентилятор лопату навоза.

Не хватает модерации этому форму. Вот на arduino.cc люди, почему-то, общаются интеллигентней


Тоись кинуть всем в лицо "ардуинщики в С++ не разбираются" и одновременно просить их же разобраться в бреде, который сам себе напридумал - верх интеллигентности штоли?

К слову, инфа для человека, разбирающегося в С++ получше всяких там ардуинщиков: сеттеры/геттеры в ООП ещё в школе учат юзать, а не лазить напрямую к членам класса.

JArduino
Offline
Зарегистрирован: 18.05.2019

Фермер пишет:

JArduino пишет:

Во-вторых, println напечатает вам чушь. Надо же сначала извлечь строку из PROGMEM.

О, спасибо! Но как лучше это сделать?

Вот полностью работающий ваш пример, если оставить класс как есть:

class A
{
public:
	const char* text;
};

#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))

void setup()
{
	A a{PSTR("Hello World!")};
	Serial.begin(9600);
	Serial.println(FPSTR(a.text));
}

void loop()
{
}

 

Фермер
Offline
Зарегистрирован: 22.01.2020
Спасибо, дружище Жардуино! Работает!
С меня пиво! :-)
 
Фермер
Offline
Зарегистрирован: 22.01.2020

DetSimen пишет:

Спрашивай, чо непонятно

 

	PFlashString classname; // имя класса сидит в PROGMEM

Идея понятна. Спасибо!
Не понятен, правда, комментарий «имя класса сидит в PROGMEM». :-)
Все оказалось просто, если разобраться что именно делают макросы PROGMEM, PSTR и F.
 
Вот что получилось, спасибо!
struct A
{
	const __FlashStringHelper* f_str;
};

void setup()
{
	A a{F("Hello World!")};
	Serial.begin(9600);
	Serial.println(a.f_str);

 

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Фермер пишет:
Объясняю: список иницилизации, фактически, вызывает default-конструтор.
Объясняю: это бред сивой кобылы. Список инициализации ничего не вызывает. Конструктор по умолчания вызывается всегда независимо от наличия или отсутствия списка инициализации. С таким пониманием вопроса ... при следующей инициализации чего-нибудь опять придёшь побираться Христа ради. Поучить он нас пришёл ....

Фермер
Offline
Зарегистрирован: 22.01.2020

Ворота пишет:

Фермер пишет:
Объясняю: список иницилизации, фактически, вызывает default-конструтор.
Объясняю: это бред сивой кобылы. Список инициализации ничего не вызывает. Конструктор по умолчания вызывается всегда независимо от наличия или отсутствия списка инициализации. С таким пониманием вопроса ... при следующей инициализации чего-нибудь опять придёшь побираться Христа ради. Поучить он нас пришёл ....

Не увидел никаких противоречий сказанному мною.

Кому интересно что это и как это работает: https://en.cppreference.com/w/cpp/language/default_constructor и  https://en.cppreference.com/w/cpp/language/initializer_list

 

JArduino
Offline
Зарегистрирован: 18.05.2019

Фермер пишет:

Спасибо, дружище Жардуино! Работает!
С меня пиво! :-)
 

Рад был помочь. Пиво сюда, пожалуйста: jarduino.ru@gmail.com

;-)

Пора открывать донат...

JArduino
Offline
Зарегистрирован: 18.05.2019
Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Фермер пишет:

Не увидел никаких противоречий сказанному мною.

Потому и не увидел, что понимания нет. Когда возникнет следующая проблема и соберёшься снова прийти на форум нас поучить, вспомни об этом.

Abbat
Abbat аватар
Offline
Зарегистрирован: 23.08.2017

Господа!

Мне показалось, что топикстартер хотел бы разместить данные (строки) в памяти программ на этапе компиляции, а вовсе не в период выполнения, поскольку никакого смысла в таком действии я не вижу: никакой экономии! Такое размещение вполне возможно и я попытаюсь проиллюстрировать это, выпилив часть своего проекта.

файл h

typedef size_t (*FuncFormat)(uint16_t);       // тип функции преобразования данных. Возвращает 
                                              // длину строки


// Структура данных в памяти программ
typedef const struct{
  const char* PROGMEM HelpTxt; // Поясняющий текст
  const uint16_t Min;          // Минимальное значение параметра
  const uint16_t Max;          // Максимальное значение параметра
  const uint16_t Divider;      // Масштабирующий коэфициент
  const uint16_t IndexDest;    // Индекс ячейки сохранения
  FuncFormat Func;             // Указатель на функцию
} TParamStruct;



// Буферная структура данных в памяти
struct TStructPrm{
  const char* PROGMEM HelpTxt=NULL; // Поясняющий текст
  uint16_t Min=0;          // Минимальное значение параметра
  uint16_t Max=0;          // Максимальное значение параметра
  uint16_t Divider=1;      // Масштабирующий коэфициент
  uint16_t IndexDest=0;    // Индекс ячейки сохранения
  FuncFormat Func=NULL;    // Указатель на функцию
};



volatile struct TStructPrm Prm;  // Структура данных в памяти данных



// Макрос для загрузки данных в память программ
#define MAKE_PRM(Name, Text, Min, Max, Div, Dest, Func) \
    const char s##Name[] PROGMEM=Text; \
    TParamStruct PROGMEM Name={s##Name, Min, Max, Div, Dest, Func} 

И файл cpp

// Некоторая функция. Возвращает 1
size_t AnyFunc( uint16_t value ){
  Debug.print("value="); Debug.print(Value);
  return 1;      
}




//Создаём блок данных ExampleDat в памяти программ
MAKE_PRM(ExampleDat, "Пример строки 12345", 1, 31, 1, 3, AnyFunc);




// Функция вывода структуры (для примера)
void OutStruct( const TParamStruct* prm ){
  uint16_t Value;

  for( uint8_t i=0; i<sizeof(TParamStruct)/sizeof(uint16_t); i++ ) // Загрузка данных из структуры 
  *((uint16_t*)&Prm+i)=pgm_read_word((uint16_t*)ps+i);             // в PROGMEM в структуру Prm
  
  Debug.print((PGM_P)Prm.HelpTxt);
 
  Value=Prm.IndexDest/Prm.Divider;

  if( Prm.Func ){ 
    Prm.Func(Value);

  Debug.print(" min_v=");Debug.print(Prm.Min);
  Debug.print(" max_v=");Debug.println(Prm.Max);    
}


// Ну и вызов этой функции
OutStruct( &ExampleDat );

Этот пример показывает как разместить структуру, состоящую из различных типов данных, в памяти программ на этапе компиляции ну и как к ней обратиться. Надеюсь, что мое сообщение будет полезно. (при "выпиливании" могли закрасться ошибки, но код работал)

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Abbat пишет:

Этот пример показывает ....

как делать не надо. 

b707
Offline
Зарегистрирован: 26.05.2017

Abbat пишет:
Этот пример показывает как разместить структуру, состоящую из различных типов данных, в памяти программ на этапе компиляции

а нафига засовывать всю строку в структуру? Почему не положить строку в Прогмем обычным образом, а в структуры вставить ссылку на нее?

Abbat
Abbat аватар
Offline
Зарегистрирован: 23.08.2017

Именно так: в структуре - ссылка на строку в памяти программ. Структура - это лишь тип данных она взята для примера. Я показал как её разместить в памяти программ на этапе компиляции и как с ней работать. Согласен, для темы инфа избыточна.

Фермер
Offline
Зарегистрирован: 22.01.2020

Я спрашивал совсем иное. С одной стороны, у меня возникла трудность использования PSTR и F в параметрах инициализации объекта, при его инициализации вне функции.

С другой стороны, я и вообще не понимал, как работает перекачка данных между SRAM и PROGMEM.

Я уже сказал, что с этим разобрался.

Что же касается первой части, то, конечно, пришлось делать все подобные инициализации внутри функции. Так это работает.

А заталкивать в PROGMEM иных структур, кроме строк, у меня необходимости пока не возникло. Но спасибо.

 

 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Было бы что и куда заталкивать , а затолкать можно многое,и в частности PROGMEM

/**/
void func_P(byte n, const char * title, ... ) {
  va_list ap;
  const char * message;
  int i = 0;
  va_start( ap, title );
  if (n == i)Serial.println((const __FlashStringHelper *)title);
  message = va_arg( ap, const char * );
  while (message) {
    ++i;
    if (n == i) Serial.println((const __FlashStringHelper *)message);
    message = va_arg( ap, const char *);
  }
  va_end( ap );
}
void aaa(byte n) {
  func_P( n,
          PSTR("Dashing through the snow,"),
          PSTR("in a one - horse open sleigh."),
          PSTR("O'er the fields we go,"),
          PSTR("laughing all the way."),
          PSTR("Bells on bobtails ring,"),
          PSTR("making spirits bright."),
          PSTR("What fun it is to ride and sing"),
          PSTR("a sleighing song tonight."),
          PSTR(""),
          PSTR("Oh! Jingle bells, jingle bells,"),
          PSTR("jingle all the way."),
          PSTR("Oh what fun it is to ride"),
          PSTR("in a one-horse open sleigh. Hey!"),
          0 //<-- конец
        );
}
void setup() {
  Serial.begin(9600);
  for (int i = 13; i >= 0; --i)aaa(i);
}

void loop() {
}