Удобный массив заголовков для HTTP-сервера

Обсуждаем контроллеры компании Atmel.
Ответить
marengo
Родился
Сообщения: 12
Зарегистрирован: Пт май 20, 2016 02:44:46

Удобный массив заголовков для HTTP-сервера

Сообщение marengo »

Здраствуйте! Пишу маленький HTTP-сервер. Столкнулся с примитивной, но нерешимой для себя задачей. Прошу помощи у знающих людей.
Спойлер

Код: Выделить всё

//file	"HeadersOfHttpResponse.h"
typedef uint16_t	HttpStatusCode;//0, 100, 200, 404, 500, ect.

struct HeadersOfHttpResponse {
	HttpStatusCode			statusCode;
	uint8_t				amountItemOfHeaders;	//количество элементов в массиве
	const char * const*		headersOfHttpResponse;
};


extern HeadersOfHttpResponse		availableHeadersOfHttpResponse[];
Спойлер

Код: Выделить всё

/file	"HeadersOfHttpResponse.cpp"
const char HTTP_1_1_200_OK_rn_pstr[] PROGMEM = "HTTP/1.1 200 OK\r\n";
const char HTTP_1_1_500_Internal_Server_Error_rn_pstr[] PROGMEM = "HTTP/1.1 500 Internal Server Error\r\n";
const char ContentType_text_html_rn_pstr[] PROGMEM = "Content-Type: text/html\r\n";



static const char * const headersOfHttpResponse_200_ok[] PROGMEM = {//массив указателей на строки, расположенные в памяти программ
	HTTP_1_1_200_OK_rn_pstr,
	ContentType_text_html_rn_pstr,
	CRLFCRLF_pstr
};

//Массив структур инициализируем сразу!
HeadersOfHttpResponse		availableHeadersOfHttpResponse[] = {//доступные HTTP-ответы
	//индекс массива 0 (приведён для примера)
	{//HTTP-код 200
		200,	//HTTP-код (StatusCode)
		3, 		//количество строк в массиве
		headersOfHttpResponse_200_ok //именованный массив указателей на строки, расположенные в памяти программ
	},
	//индекс массива 1. Ничем не отличается от нулевого, кроме способа инициализации указателя на массив указателей
	{//HTTP-код 200
		200,	//HTTP-код (StatusCode)
		3, 		//количество строк в массиве
		(const char * const[]) {//анонимный массив указателей на строки, расположенные в памяти программ
			HTTP_1_1_200_OK_rn_pstr, 
			ContentType_text_html_rn_pstr, 
			CRLFCRLF_pstr
		}
	},
	//индекс массива 2
	{//HTTP-код 500
		500,		//HTTP-код (StatusCode)
		3,  		//количество строк в массиве
		(const char * const[]){//анонимный массив указателей на строки, расположенные в памяти программ
			HTTP_1_1_500_Internal_Server_Error_rn_pstr, 
			ContentType_text_html_rn_pstr, 
			CRLFCRLF_pstr
		}
	},
};
Кратко опишу весь этот "зоопарк".
"availableHeadersOfHttpResponse[]" — глобальный массив доступных в программе HTTP-ответов. Когда сервер решает ответить на запрос, например,
кодом "200", то он ищет соответствие среди элементов данного массива. И отправляет соответствующие строки заголовков, а потом уже запрошенный файл. Строки распологаются в памяти программ.

Собственно, код компилируется без варнингов. Компилятор (AVR Studio v4.19) молчит как партизан.
Чтение строк массива "availableHeadersOfHttpResponse[0].headersOfHttpResponse" происходит корректно.
А вот чтение строк из массивов "availableHeadersOfHttpResponse[1].headersOfHttpResponse" и "availableHeadersOfHttpResponse[2].headersOfHttpResponse" выдаёт
всё что угодно, но только не то что надо! Я так понимаю указатель ".headersOfHttpResponse" указывает куда-то не туда. :)))
Так вот вопрос.
Как обойтись только анонимными массивами, без массивов типа "static const char * const headersOfHttpResponse_200_ok[] PROGMEM"?
Методом научного тыка, перепробовал массу разных комбинаций.
Реклама
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Удобный массив заголовков для HTTP-сервера

Сообщение Kavka »

Хм... Ну, очень вероятно, вы неправильно "достаёте" строки.
Банально дам ссылку, проверьте всё ещё раз. И проверьте как вы достаёте строки из флэша.
https://www.microchip.com/webdoc/AVRLib ... rings.html
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Удобный массив заголовков для HTTP-сервера

Сообщение ARV »

пора отказываться от геморроя с pgm_read_xxx, применяйте модификатор __flash и работайте полноценно с "переменными" во flash и указателями на данные там же.
модификатор __flash__memx, кстати - тоже неплохая фишка) доступен с версии avr-gcc 5.x.x (по-моему, сам я на 6-й сижу, но есть уже и 8).
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Удобный массив заголовков для HTTP-сервера

Сообщение Kavka »

Ну, да и это тоже в тему.
https://gcc.gnu.org/onlinedocs/gcc/Name ... ess-Spaces
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
GoldenAndy
Поставщик валерьянки для Кота
Сообщения: 1925
Зарегистрирован: Чт июл 28, 2016 07:58:37
Откуда: Kyiv, UA
Контактная информация:

Re: Удобный массив заголовков для HTTP-сервера

Сообщение GoldenAndy »

ARV писал(а):применяйте модификатор __flash
Походу это те же яйца, только в профиль.
Обертка того же pgm_read'а. В обоих случаях компилятор сотворит закидывание адреса чтения в ZL,ZH и выполнит LPM Rxx, Z[+]
Причем меня сильно гложет сомнение, что если читать циклом массив данных, то gcc поймет это и будет использовать директиву с автоинкрементом Z.
С __flash не пробовал, но вот такую конструкцию

Код: Выделить всё

	while(counter) {
		*(ram++) = pgm_read_byte(pgm++);
		counter--;
	}
компилятор разворачивает в отдельный LPM Rxx,Z и отдельный инкремент Z-пары

Код: Выделить всё

	while(counter) {
00002189  MOVW R30,R22		Copy register pair 
0000218A  TST R20		Test for Zero or Minus 
0000218B  BREQ PC+0x08		Branch if equal 
		*(ram++) = pgm_read_byte(pgm++);
0000218C  LPM R18,Z		Load program memory 
0000218D  MOVW R26,R24		Copy register pair 
0000218E  ST X+,R18		Store indirect and postincrement 
0000218F  MOVW R24,R26		Copy register pair 
		counter--;
00002190  SUBI R20,0x01		Subtract immediate 
00002191  ADIW R30,0x01		Add immediate to word 
00002192  RJMP PC-0x0008		Relative jump 
}
И я не уверен, что __flash скомпилируется по другому. Но pgm_read дает более полное понимание того, что делается.
ИзображениеИзображение
Изображение
 
Telegram               Лучшая благодарность ->
[+]
Реклама
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: Удобный массив заголовков для HTTP-сервера

Сообщение oleg110592 »

Компилятор (AVR Studio v4.19)
наверное старенький или WinAVR или старый тулчейн от А
делал когда-то по
http://www.tuxgraphics.org/electronics/ ... 6111.shtml
Спойлер

Код: Выделить всё

// prepare the webpage by writing the data to the tcp send buffer
uint16_t print_webpage(uint8_t *buf,uint8_t on_off)
{
        uint16_t plen;
        plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"));
        plen=fill_tcp_data_p(buf,plen,PSTR("<center><p>Output is: "));
        if (on_off){
                plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#00FF00\"> ON</font>"));
        }else{
                plen=fill_tcp_data_p(buf,plen,PSTR("OFF"));
        }
        plen=fill_tcp_data_p(buf,plen,PSTR(" <small><a href=\".\">[refresh status]</a></small></p>\n<p><a href=\"."));
        if (on_off){
                plen=fill_tcp_data_p(buf,plen,PSTR("/0\">Switch off</a><p>"));
        }else{
                plen=fill_tcp_data_p(buf,plen,PSTR("/1\">Switch on</a><p>"));
        }
        plen=fill_tcp_data_p(buf,plen,PSTR("</center><hr><br>version 2.17, tuxgraphics.org\n"));
        return(plen);
} 

Код: Выделить всё

// fill in tcp data at position pos. pos=0 means start of
// tcp data. Returns the position at which the string after
// this string could be filled.
uint16_t fill_tcp_data_p(uint8_t *buf,uint16_t pos, const prog_char *progmem_s)
{
        char c;
        // fill in tcp data at position pos
        //
        // with no options the data starts after the checksum + 2 more bytes (urgent ptr)
        while ((c = pgm_read_byte(progmem_s++))) {
                buf[TCP_CHECKSUM_L_P+3+pos]=c;
                pos++;
        }
        return(pos);
} 
Реклама
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Удобный массив заголовков для HTTP-сервера

Сообщение ARV »

goldenandy писал(а):И я не уверен, что __flash скомпилируется по другому. Но pgm_read дает более полное понимание того, что делается.
я вас уверяю, что не смотря на то, что компилятор делает то же самое, для вас более полное понимание того, что делается, будет именно в случае __flash.

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

Код: Выделить всё

const __flash my_struct *ptr = &my_array_from_flash;

if(ptr[1]->my_field->name != NULL) pfintf_P(PSTR("Name = %S"), ptr[1]->my_field->name);
c использованием pgm_read_xxxx... думаю, у вас будет такой огород преобразования типов, и все равно разыменование указателей из FLASH так просто не получится сделать без промежуточных pgm_read_xxxx...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
GoldenAndy
Поставщик валерьянки для Кота
Сообщения: 1925
Зарегистрирован: Чт июл 28, 2016 07:58:37
Откуда: Kyiv, UA
Контактная информация:

Re: Удобный массив заголовков для HTTP-сервера

Сообщение GoldenAndy »

ARV писал(а):более полное понимание того, что делается, будет именно в случае __flash
Может быть, тут уж кто как привык.

Я железнозависимые вещи вообще стараюсь выносить в HAL либо в другую библиотеку.
Там один раз чтение обернуть в макрос или функцию - и забыть.

для основной программы это вообще должно быть некоей функцией getHttpResponseStr(unsigned char responseIndex, char* responseBuf);

А хранить массив строк во флеше AVR'ок можно либо объявив каждую строку как свой массив и потом сложить массив указателей на строки, либо пожертвовать неким объемом флеша и объявить двумерный массив с явным указанием максимальной длины строк...

Код: Выделить всё

const __flash my_stringArr[][160] = {"String one", "Strung two", Superstring"};
ИзображениеИзображение
Изображение
 
Telegram               Лучшая благодарность ->
[+]
Ответить

Вернуться в «AVR»