Комментарии 64
как впихнуть невпихуемое и отобразить в реальном времени трехмерную графику при помощи контроллера, у которого недостаточно ни скорости, ни памяти для этого.
Это громко сказано… про недостаточность памяти и скорости. Если сравнить со "спектрум" Z80.
Игрушки были приличные.
А на счет Спектрума — мне казалось, у него все-таки была какая-то аппаратная видеокарта. Да и вообще специфика разная.
У Спектрума аппаратная часть на рассыпухе "отображала" часть ОЗУ в видеосигналы (если упрощенно).
С учетом того, что ili9341 это то же память + аппаратная часть, а запись через SPI + DMA в ОЗУ ili9341, в общем то, сравнима с прямой записью в ОЗУ на типичных 8Мгц Z80…
Те же яйца, только вид сбоку.
И я не принял серьезно :) Вот если бы на AVR 8 битовом… что гораздо ближе к Спектруму по быстродействию и памяти.
Так-то AVR8, без зазрения совести:
Ну и сравнивать RISC с z80…
и возведения в половинную степень вместо извлечения корня
Это разные записи одной и той же операции
А есть бенчмарки?
Я сильно сомневаюсь, что более универсальная функция pow() оптимизирована лучше специализированной sqrt(). Тем более, что последняя на многих платформах реализована аппаратно.
Если уж говорить про "грязную скорость" sqrt() (вернее 1/sqrt(), что более востребовано), то вспоминать нужно про 0x5f3759df
Заодно вопхну сюда ответ на вопрос про число PI, поскольку набежавшие в срачик про мед. маски «специалисты по всем вопросам» подслили карму и писать комменты получается теперь не чаще раза в час.
Эта квейковская загогулина работает не только лишь везде, а вообще мало где. Она расчитана под чистый, незамутнённый 32-битный float, и ни на что больше
Именно поэтому это грязный хак изящная чертова магия.
В принципе подобную магию можно сотворить и под float64, но особого смысла это не имеет, т.к. метод дает приближенное значение обратного корня и точности float32 более чем достаточно.
Бенчмарки надо разумеется писать
раз вы утверждаете, что a быстрее b, то либо вы бенчмарки писали/проводили, либо ваше утверждение голословно
оператора возведения в степень "^", который я использовал вместо math.pow()
я не знаю, про какой именно язык программирования вы говорите, но в любом случае бинарный оператор это просто сахар для вызова функции/метода.
я не знаю, про какой именно язык программирования вы говорите, но в любом случае бинарный оператор это просто сахар для вызова функции/метода.
Я там опечатался в ответе. Не math.pow() имелось в виду, а math.sqrt(), по сравнению с оператором "^". Ну, немного подредактировав бенчмарки, можно сравнить например «math.pow(a)» c «a*a» и с «a^2». Касательно квадратного корня получилось вот так:
local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
b = math.sqrt(35.73)
end
a = os.clock() - a
print (a)
lua ./sqrt_lua.lua
14.738681
luajit ./sqrt_lua.lua
0.073986
local sqrt = math.sqrt
local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
b = sqrt(35.73)
end
a = os.clock() - a
print (a)
lua ./local_sqrt_lua.lua
9.867505
luajit ./local_sqrt_lua.lua
0.073703
local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
b = 35.73^0.5
end
a = os.clock() - a
print (a)
lua ./test_operator.lua
2.276411
luajit ./test_operator.lua
0.073202
Это прекрасно во всем: и использование lua для теста числодробильни и надежда на то, что 35.73^0.5 вычисляется более одного раза при интерпретации (и хотябы один раз в скомпилированном коде).
замените код вашего бенчмарка хотябы на
local a = os.clock()
local b = 100.0
for i = 1, 100000000 do
b = math.sqrt(b)*10.0
end
a = os.clock() - a
print (a)
local a = os.clock()
local b = 100.0
for i = 1, 100000000 do
b = (b^0.5)*10.0
end
a = os.clock() - a
print (a)
и поделитесь результатом )
1) Как в lua из массива чисел (иногда с части элементов массива, идущих подряд) сделать строку из их символьных представлений? Сейчас я прогоняю циклом и каждый раз прибавляю к строке один символ, полученный через string.char от элемента массива (как-то так функция называется — пишу по памяти, так как прошивка на другом компьютере). Память кушает хорошо. Это нужно потому, что функции передачи данных работают почему-то со строками. А у меня массив байт.
2) Можно ли создать массив не задавая его элементы в цикле? А то приходится for n=1,1000,1 do a[n]=0 end делать. Как-то это не очень красиво. Память массивы тоже кушают отлично… А постоянно расширять массив a[#a+1]=byte не вариант по скорости. Я теперь сразу выделяю кусок под принятые данные в размер максимального пакета.
3) Если вы работали с модулем esp8266, то вызывает удивление передача на сервер данных через conn:send. Секундная задержка между вызовом функции send (я передаю где-то по 450 байт за раз) и вызовом функции обратного вызова, подтверждающей приём — это как-то странно. На прошивке с AT-командами такого не было (там сама прошивка вешалась периодически). Я догадываюсь, что дело может быть в том, что модуль ждёт не наберётся ли полный пакет, но как бы это отключить (такое я видел, например, в сокетном API QNX) и инициировать передачу сразу же. Или есть какой-то другой способ передачи без задержек из lua (в AT-прошивке как-то же это сделано)?
Спасибо.
Судя по всему, вы хорошо знакомы с lua
В основном на уровне написания скриптиков для openwrt. Python что-то более серьезное там развернуть ресурсов маловато, а писать на баше у меня борода недостаточно густая. На вопросы попробую ответить, но порядок придется нарушить.
2) Можно ли создать массив не задавая его элементы в цикле?
В Lua в принципе нельзя создать массив (в понимании C). Нет там такого типа данных. Есть ассоциативные массивы (tables), т.е. хранилища пар ключ(любого типа) — значение(любого типа). Если в качестве ключа вы будете использовать number, то получите типа массив. Но это не будут последовательно расположенные в памяти элементы. оверхэд такого решения вы почувствовали и сами. Инициализируете вы такой "массив" правильно.
1) Как в lua из массива чисел (иногда с части элементов массива, идущих подряд) сделать строку из их символьных представлений?
Как вы понимаете, раз нет никаких массивов, то нет и никакого 'подряд', поэтому и строку вы получаете правильно.
3) Если вы работали с модулем esp8266
Если речь про NodeMCU, то нет
ps:
Вышесказанное относилось к 'прикладному' Lua. Используя функции Lua C API, предназначенные для манипуляции с данными получаемыми/передаваемыми из внешних библиотек, теоретически возможно все это серьезно заоптимизировать. Но это (на мой взгляд) подобно сексу в гамаке стоя. Ибо зачем так извращаться, когда можно просто написать нужное на C/C++. Под ту же ESP есть ряд фреймворков, в том числе с низким порогом входа. Та же Arduino.
Что касается С++ для ESP, то что-то я подозреваю, что запуск TCP и WIFI не будут простыми. Впрочем, надо посмотреть. :)
habr.com/ru/post/113804
habr.com/ru/post/113804
Цикл можно ускорить при помощи простого трюка
for i=0, 1000, 10 do
a[i]=0
a[i+1]=0
...
a[i+9]=0
end
О, специалист по оптимизации подтянулся.
Поковыряйте Luajit с FFI
А что, на встроенную в NodeMCU Lua завезли Luajit ?
Цикл можно ускорить при помощи простого трюка
И как же в данном случае разворачивание цикла его ускорит ?
Сложность работы в первую очередь не от языка зависит, а от используемого фреймворка. Это не синонимы. Если писать на C, используя espressif sdk — будет не очень легко, если использовать arduino, то весь пример "мост tcp-serial" https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino по мне выглядит проще, чем заняться с творческой перепаковкой данных на lua.
Если писать на C, используя espressif sdk — будет не очень легко
Я, собственно, это и имею в виду. :) Если в SDK есть компоненты достаточно высокоуровневой сокетной библиотеки, то всё будет просто. А вот если нет…
по мне выглядит проще, чем заняться с творческой перепаковкой данных на lua.
Так я не использую Arduino. :) А простое соединение я сделал и так, но меня не устроила скорость работы в lua функции send.
Впрочем, пример мигания на Си у меня откомпилировался и заработал. :)
А на lua я такое написал пока что:
--****************************************************************************************************
--глобальные переменные
--****************************************************************************************************
ReceivedArray={}--принятые байты данных
ReceivedArraySize=0;--количество принятых данных
StuffingOn=false--включёна ли замена байт
BEGIN_PACKAGE=0xff--начало пакета
END_PACKAGE=0x00--конец пакета
STUFFING_ON=0xfe--включение стаффинга
MAX_RECEIVED_ARRAY=512--максимальный размер принятого пакета с данными
SCK=nil
--****************************************************************************************************
--функции
--****************************************************************************************************
------------------------------------------------------------------------------------------------------
--произошло подключение к серверу
------------------------------------------------------------------------------------------------------
function OnConnect(sck,c)
SCK=sck
local answer={string.byte("C",1),string.byte("O",1)}
UARTTransmitt(answer)
end
------------------------------------------------------------------------------------------------------
--произошло отключение от сервера
------------------------------------------------------------------------------------------------------
function OnDisconnect(sck,c)
SCK=nil
local answer={string.byte("D",1),string.byte("O",1)}
UARTTransmitt(answer)
end
------------------------------------------------------------------------------------------------------
--завершена передача данных
------------------------------------------------------------------------------------------------------
function OnSend(sck,c)
local answer={string.byte("S",1),string.byte("O",1)}
UARTTransmitt(answer)
end
------------------------------------------------------------------------------------------------------
--получены данные
------------------------------------------------------------------------------------------------------
function OnReceive(sck,c)
end
------------------------------------------------------------------------------------------------------
--настройка UART
------------------------------------------------------------------------------------------------------
function UARTSetting()
uart.setup(0,115200*8,8,0,1,0)
uart.on("data",1,UARTReceive,0)
end
------------------------------------------------------------------------------------------------------
--передача данных по UART с заменой байт
------------------------------------------------------------------------------------------------------
function UARTTransmitt(data)
local length=#data
local send=""
send=send..string.char(BEGIN_PACKAGE)
for n=1,length,1 do
local byte=data[n]
if (byte==BEGIN_PACKAGE or byte==END_PACKAGE or byte==STUFFING_ON) then
send=send..string.char(STUFFING_ON)
end
send=send..string.char(byte)
end
send=send..string.char(END_PACKAGE)
uart.write(0,send)
send=nil
collectgarbage()
end
------------------------------------------------------------------------------------------------------
--анализ полученной команды
------------------------------------------------------------------------------------------------------
function ExecuteCommand()
local command=ReceivedArray[1]
if (command==string.byte("C",1)) then--Connect
if (SCK~=nil) then
local answer={command,string.byte("O",1)}--уже подключено
UARTTransmitt(answer)
return
end
local port=ReceivedArray[2]+ReceivedArray[3]*256;
local ip=string.format("%i.%i.%i.%i",ReceivedArray[4],ReceivedArray[5],ReceivedArray[6],ReceivedArray[7]);
conn=net.createConnection(net.TCP,0)
conn:on("connection",OnConnect)
conn:on("receive",OnReceive)
conn:on("disconnection",OnDisconnect)
conn:on("sent",OnSend)
conn:connect(port,ip)
return
end
if (command==string.byte("D",1)) then--Disconnect
if (SCK==nil) then
local answer={command,string.byte("E",1)}
UARTTransmitt(answer)
return
end
SCK:close()
SCK=nil
collectgarbage()
local answer={command,string.byte("O",1)}
UARTTransmitt(answer)
return
end
if (command==string.byte("S",1)) then--Send
if (SCK==nil) then
local answer={command,string.byte("E",1)}
UARTTransmitt(answer)
return
end
--for n=2,ReceivedArraySize,1 do
--SCK:send(string.char(ReceivedArray[n]))
--end
local send=""
for n=2,ReceivedArraySize,1 do
send=send..string.char(ReceivedArray[n])
end
SCK:send(send)
send=nil
collectgarbage()
return
end
if (command==string.byte("T",1)) then--Test
local answer={command,string.byte("O",1)}
UARTTransmitt(answer)
end
end
------------------------------------------------------------------------------------------------------
--получение данных с UART
------------------------------------------------------------------------------------------------------
function UARTReceive(data)
--используем протокол с байтстаффингом
if (ReceivedArraySize>MAX_RECEIVED_ARRAY) then--начинаем приём заново при превышении размера массива
ReceivedArraySize=0
StuffingOn=false
end
local byte=string.byte(data,1)
if (StuffingOn==false) then
if (byte==BEGIN_PACKAGE) then--начало приёма
ReceivedArraySize=0
return
end
if (byte==END_PACKAGE) then--конец приёма
if (ReceivedArraySize>0) then
ExecuteCommand()
end
ReceivedArraySize=0
return
end
if (byte==STUFFING_ON) then--включение замены байт
StuffingOn=true
return
end
ReceivedArray[ReceivedArraySize+1]=byte
ReceivedArraySize=ReceivedArraySize+1
return
end
--замена байт включена
StuffingOn=false
--если принят неизвестный код, начинаем приём заново
if (byte~=BEGIN_PACKAGE) and (byte~=END_PACKAGE) and (byte~=STUFFING_ON) then
ReceivedArraySize=0
return
end
ReceivedArray[ReceivedArraySize+1]=byte
ReceivedArraySize=ReceivedArraySize+1
end
------------------------------------------------------------------------------------------------------
--вывод полученного IP-адреса
------------------------------------------------------------------------------------------------------
function ShowIP(params)
print("My IP is " .. params.IP)
end
------------------------------------------------------------------------------------------------------
--вывод списка найденных сетей
------------------------------------------------------------------------------------------------------
function ShowWiFiNet(table)
for ssid,v in pairs(table) do
authmode,rssi,bssid,channel=string.match(v,"(%d),(-?%d+),(%x%x:%x%x:%x%x:%x%x:%x%x:%x%x),(%d+)")
print(ssid,authmode,rssi,bssid,channel)
end
end
------------------------------------------------------------------------------------------------------
--произведено подключение к роутеру
------------------------------------------------------------------------------------------------------
function RouterConnect(params)
ShowIP(params)
wifi.sta.getap(ShowWiFiNet)
UARTSetting()
end
--****************************************************************************************************
--начало программы
--****************************************************************************************************
tmr.softwd(-1)
tmr.wdclr()
--создаём массив принятых данных
for n=1,MAX_RECEIVED_ARRAY,1 do
ReceivedArray[n]=0
end
ReceivedArraySize=0
local heap_size=node.heap()
print(" Free memory:",heap_size,"\r\n")
wifi.setmode(wifi.STATION)
station_cfg={}
station_cfg.ssid="FPV_WIFI__D49A"
station_cfg.pwd=""
station_cfg.save=false
station_cfg.got_ip_cb=RouterConnect
wifi.sta.config(station_cfg)
--local heap_size=node.heap()
--print("ReceivedArray:",#ReceivedArray," Free:",heap_size,"\r\n")
Но поскольку я использую си++ и компилятор для esp8266 запустился, то я на си++ дальше и попробую сделать прошивку. :) А lua останется так, как рудимент.
Так я не использую Arduino
По религиозным соображениям?
На всякий случай уточню — под arduino я имел в виду не отдельную плату (на AVR), к которой подключается ESP, а ESP8266 Arduino core. Где есть все обертки над espressif SDK в привычной ардуинщикам форме + возможность использовать кучу библиотек для разной периферии.
Да, конечно, используя голый SDK теоретически можно делать интереснее и лучше. Но подозреваю, что практически это будет наполнено существенно большей болью.
По религиозным соображениям?
Потому что, обычно, могу позволить себе не использовать. :)
ESP8266 Arduino core.
Спасибо, гляну, что там внутри.
Да, конечно, используя голый SDK теоретически можно делать интереснее и лучше. Но подозреваю, что практически это будет наполнено существенно большей болью.
Пока не знаю — ещё не смотрел SDK.
С энергосберегающим режимом очень правдоподобная гипотеза. При отправке первого пакета. И второго, если он отправляется через продолжительное время. Но отправка полмегабайта в минуту — явно не тот случай. Да и на памятежор, как вы понимаете, powersave влиять не может.
Рад, что у вас получилось.
Этот код подключается по WiFi к роутеру и по командам по UART соединяется/отключается с заданным сервером и передаёт данные. А вот приём ответа от сервера мне не нужен — я событие вывел, но по UART обратно данные не отправляю.
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <stdio.h>
#include <string.h>
#include <osapi.h>
#include <os_type.h>
#include <uart.h>
//#include <mem.h>
#include <ip_addr.h>
#include <espconn.h>
#include "user_interface.h"
#include "led.h"
#include "uart.h"
//****************************************************************************************************
//макроопределения
//****************************************************************************************************
#define WIFI_CLIENTSSID "name"
#define WIFI_CLIENTPASSWORD "password"
//максимальный размер принятого пакета с данными
#define MAX_RECEIVED_ARRAY 512
//максимальный размер передаваемого пакета с данными
#define MAX_TRANSMITT_ARRAY 512
//****************************************************************************************************
//перечисления
//****************************************************************************************************
typedef enum
{
WIFI_STATE_CONNECTING,//WiFi подключается к роутеру
WIFI_STATE_CONNECTING_ERROR,//ошибка подключения WiFi к роутеру
WIFI_STATE_CONNECTED,//WiFi подключён к роутеру
WIFI_STATE_TCP_CONNECTED//установлено TCP-соединение
} WIFI_STATE;
//****************************************************************************************************
//константы
//****************************************************************************************************
static const uint8_t BEGIN_PACKAGE=0xff;//начало пакета
static const uint8_t END_PACKAGE=0x00;//конец пакета
static const uint8_t STUFFING_ON=0xfe;//включение замены байт
//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
static uint8_t ReceivedArray[MAX_RECEIVED_ARRAY];//принятые байты данных
static uint8_t TransmittArray[MAX_TRANSMITT_ARRAY];//буфер данных для отправки
static size_t ReceivedArraySize=0;//количество принятых данных
static bool StuffingOn=false;//включёна ли замена байт
static WIFI_STATE WiFi_State=WIFI_STATE_CONNECTING;
static os_timer_t WiFi_CheckIPTimer;//таймер проверки IP сети WiFi
static struct espconn ESPConnection;
static esp_tcp ESPConnectionTCP;
//****************************************************************************************************
//прототипы функций
//****************************************************************************************************
static void ICACHE_FLASH_ATTR UART_Transmitt(const uint8_t *data,size_t size);//отправить по UART данные с заменой байт
static void ICACHE_FLASH_ATTR UART_TransmittMessage(const char *str);//передать по UART текствовое сообщение с заменой байт
static void ICACHE_FLASH_ATTR UART_ExecuteCommand(const uint8_t *command_ptr,size_t size);//выполнение команды, пришедшей по UART
static void ICACHE_FLASH_ATTR UART_PushByte(uint8_t byte);//разбор принятых данных по UART
static void UART_OnReceived(const uint8_t *data,size_t size);//пришли новые данные по UART
static void UART_OnSendDone(void);//UART закончил передачу данных
static void ICACHE_FLASH_ATTR WiFi_StopTimer(void);//отключить проверку WiFi
static void ICACHE_FLASH_ATTR WiFi_StartTimer(size_t interval_ms);//запустить таймер проверки WiFi
static void ICACHE_FLASH_ATTR WiFi_OnSendDone(void* arg);//завершена передача данных по TCP
static void ICACHE_FLASH_ATTR WiFi_OnReceived(void* arg, char* pusrdata, uint16_t length);//пришли данные по TCP
static void ICACHE_FLASH_ATTR WiFi_OnConnectedTCP(void* arg);//произведено подключение по TCP
static void ICACHE_FLASH_ATTR WiFi_OnDisconnectedTCP(void* arg);//произведено отключение по TCP
static void ICACHE_FLASH_ATTR WiFi_CheckIP(void *arg);//периодическая проверка IP
//****************************************************************************************************
//реализация функций
//****************************************************************************************************
//----------------------------------------------------------------------------------------------------
//реализация системной функции, необходимой SDK
//----------------------------------------------------------------------------------------------------
uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void)
{
enum flash_size_map size_map=system_get_flash_size_map();
uint32 rf_cal_sec=0;
switch(size_map)
{
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec=128-8;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec=256-5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec=512-5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec=1024-5;
break;
default:
rf_cal_sec=0;
break;
}
return(rf_cal_sec);
}
//----------------------------------------------------------------------------------------------------
//отправить по UART данные с заменой байт
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_Transmitt(const uint8_t *data,size_t size)
{
size_t transmitt_size=0;
size_t n;
TransmittArray[transmitt_size]=BEGIN_PACKAGE;
transmitt_size++;
for(n=0;n<size;n++)
{
uint8_t byte=data[n];
if (byte==BEGIN_PACKAGE || byte==END_PACKAGE || byte==STUFFING_ON)
{
TransmittArray[transmitt_size]=STUFFING_ON;
if (transmitt_size+3>MAX_TRANSMITT_ARRAY) break;
transmitt_size++;
}
TransmittArray[transmitt_size]=byte;
if (transmitt_size+2>MAX_TRANSMITT_ARRAY) break;
transmitt_size++;
}
TransmittArray[transmitt_size]=END_PACKAGE;
transmitt_size++;
UART_SendData(TransmittArray,transmitt_size);
}
//----------------------------------------------------------------------------------------------------
//передать по UART текствовое сообщение с заменой байт
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_TransmittMessage(const char *str)
{
UART_Transmitt((uint8_t*)str,strlen(str));
}
//----------------------------------------------------------------------------------------------------
//отключить проверку WiFi
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_StopTimer(void)
{
os_timer_disarm(&WiFi_CheckIPTimer);
}
//----------------------------------------------------------------------------------------------------
//запустить таймер проверки WiFi
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_StartTimer(size_t interval_ms)
{
os_timer_setfn(&WiFi_CheckIPTimer,(os_timer_func_t *)WiFi_CheckIP,NULL);
os_timer_arm(&WiFi_CheckIPTimer,interval_ms,0);
}
//------------------------------------------------------
//завершена передача данных по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnSendDone(void* arg)
{
UART_TransmittMessage("SO");
}
//------------------------------------------------------
//пришли данные по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnReceived(void* arg, char* pusrdata, uint16_t length)
{
}
//------------------------------------------------------
//произведено подключение по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnConnectedTCP(void* arg)
{
UART_TransmittMessage("CO");
UART_SendMessage("TCP connected\r\n");
WiFi_State=WIFI_STATE_TCP_CONNECTED;
}
//------------------------------------------------------
//произведено отключение по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnDisconnectedTCP(void* arg)
{
UART_TransmittMessage("DO");
WiFi_State=WIFI_STATE_CONNECTED;
}
//----------------------------------------------------------------------------------------------------
//выполнение команды, пришедшей по UART
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_ExecuteCommand(const uint8_t *command_ptr,size_t size)
{
if (size==7)
{
if (command_ptr[0]=='C')//подключение к серверу
{
if (WiFi_State==WIFI_STATE_TCP_CONNECTED)//соединение уже было произведено
{
UART_TransmittMessage("CO");
return;
}
if (WiFi_State!=WIFI_STATE_CONNECTED)//нет соединения с роутером
{
UART_TransmittMessage("CE");
return;
}
//подключаемся к серверу
WiFi_StopTimer();
ESPConnection.proto.tcp=&ESPConnectionTCP;
ESPConnection.type=ESPCONN_TCP;
ESPConnection.state=ESPCONN_NONE;
uint16_t port=command_ptr[2];
port<<=8;
port|=command_ptr[1];
uint8_t ip_str[4*4+1];//4 раза 4 символа (3 цифры с точкой) и завершающий ноль
os_sprintf(ip_str,"%i.%i.%i.%i",command_ptr[3],command_ptr[4],command_ptr[5],command_ptr[6]);
UART_SendMessage("Connected:");
UART_SendMessage(ip_str);
UART_SendMessage("\r\n");
uint32_t ip=ipaddr_addr(ip_str);
os_memcpy(ESPConnection.proto.tcp->remote_ip,&ip,sizeof(uint32_t));
ESPConnection.proto.tcp->local_port=espconn_port();
ESPConnection.proto.tcp->remote_port=port;
//espconn_create(&pConn);
espconn_regist_sentcb(&ESPConnection,WiFi_OnSendDone);
espconn_regist_recvcb(&ESPConnection,WiFi_OnReceived);
espconn_regist_connectcb(&ESPConnection,WiFi_OnConnectedTCP);
espconn_regist_disconcb(&ESPConnection,WiFi_OnDisconnectedTCP);
//espconn_regist_write_finish(pespconn,user_tcp_write_finish);
//espconn_regist_write_finish(pespconn, user_tcp_write_finish); // register write
//espconn_regist_disconcb(pespconn, user_tcp_discon_cb);
//espconn_set_opt(pespconn, 0x04); // enable write buffer
//espconn_regist_write_finish(pespconn, user_tcp_write_finish); // register write
espconn_connect(&ESPConnection);
WiFi_StartTimer(1000);
return;
}
}
if (size==1)
{
if (command_ptr[0]=='D')//отключение от сервера
{
if (WiFi_State!=WIFI_STATE_TCP_CONNECTED)
{
UART_TransmittMessage("DE");
return;
}
espconn_disconnect(&ESPConnection);
return;
}
}
if (size>1)
{
if (command_ptr[0]=='S')//передача данных на сервер
{
if (WiFi_State!=WIFI_STATE_TCP_CONNECTED)
{
UART_TransmittMessage("SE");
return;
}
espconn_send(&ESPConnection,(uint8_t*)(command_ptr+1),size-1);
return;
}
}
}
//----------------------------------------------------------------------------------------------------
//разбор принятых данных по UART
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_PushByte(uint8_t byte)
{
if (ReceivedArraySize>MAX_RECEIVED_ARRAY)//начинаем приём заново при превышении размера массива
{
ReceivedArraySize=0;
StuffingOn=false;
}
if (StuffingOn==false)
{
if (byte==BEGIN_PACKAGE)//начало приёма
{
ReceivedArraySize=0;
return;
}
if (byte==END_PACKAGE)//конец приёма
{
if (ReceivedArraySize>0) UART_ExecuteCommand(ReceivedArray,ReceivedArraySize);
ReceivedArraySize=0;
return;
}
if (byte==STUFFING_ON)//включение замены байт
{
StuffingOn=true;
return;
}
ReceivedArray[ReceivedArraySize]=byte;
ReceivedArraySize++;
return;
}
//замена байт включена
StuffingOn=false;
//если принят неизвестный код, начинаем приём заново
if ((byte!=BEGIN_PACKAGE) && (byte!=END_PACKAGE) && (byte!=STUFFING_ON))
{
ReceivedArraySize=0;
return;
}
ReceivedArray[ReceivedArraySize]=byte;
ReceivedArraySize++;
}
//----------------------------------------------------------------------------------------------------
//пришли новые данные по UART
//----------------------------------------------------------------------------------------------------
static void UART_OnReceived(const uint8_t *data,size_t size)
{
size_t n;
for(n=0;n<size;n++) UART_PushByte(data[n]);
}
//----------------------------------------------------------------------------------------------------
//UART закончил передачу данных
//----------------------------------------------------------------------------------------------------
static void UART_OnSendDone(void)
{
}
//----------------------------------------------------------------------------------------------------
//системная функция: пред-инициализация
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR user_rf_pre_init(void)
{
}
//----------------------------------------------------------------------------------------------------
//периодическая проверка IP
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_CheckIP(void *arg)
{
struct ip_info ipConfig;
WiFi_StopTimer();
uint8_t wifi_status=wifi_station_get_connect_status();//узнаем состояние соединения с точкой доступа
if (wifi_status==STATION_GOT_IP)
{
wifi_get_ip_info(STATION_IF,&ipConfig);
if (ipConfig.ip.addr!=0)
{
if (WiFi_State!=WIFI_STATE_CONNECTED && WiFi_State!=WIFI_STATE_TCP_CONNECTED)
{
WiFi_State=WIFI_STATE_CONNECTED;
LED_On();
char str[255];
os_sprintf(str,"My IP:%i.%i.%i.%i\r\n",ipConfig.ip.addr&0xff,(ipConfig.ip.addr>>8)&0xff,(ipConfig.ip.addr>>16)&0xff,(ipConfig.ip.addr>>24)&0xff);
UART_SendMessage(str);
return;
}
else
{
LED_Off();
}
}
}
else
{
LED_Off();
WiFi_State=WIFI_STATE_CONNECTING;
espconn_delete(&ESPConnection);
if (wifi_station_get_connect_status()==STATION_WRONG_PASSWORD)
{
WiFi_State=WIFI_STATE_CONNECTING_ERROR;
UART_SendMessage("STATION_WRONG_PASSWORD\r\n");
}
if(wifi_station_get_connect_status()==STATION_NO_AP_FOUND)
{
WiFi_State=WIFI_STATE_CONNECTING_ERROR;
UART_SendMessage("STATION_NO_AP_FOUND\r\n");
}
if(wifi_station_get_connect_status()==STATION_CONNECT_FAIL)
{
WiFi_State=WIFI_STATE_CONNECTING_ERROR;
UART_SendMessage("STATION_CONNECT_FAIL\r\n");
}
if (wifi_station_get_connect_status()!=STATION_WRONG_PASSWORD &&
wifi_station_get_connect_status()!=STATION_NO_AP_FOUND &&
wifi_station_get_connect_status()==STATION_CONNECT_FAIL)
{
WiFi_State=WIFI_STATE_CONNECTING;
}
WiFi_StartTimer(500);
}
}
//----------------------------------------------------------------------------------------------------
//инициализация WiFi
//----------------------------------------------------------------------------------------------------
void WiFi_Init(void)
{
wifi_set_opmode_current(STATION_MODE);
wifi_station_disconnect();
wifi_station_dhcpc_stop();
WiFi_StopTimer();
struct station_config stationConf;
os_memset(&stationConf,0,sizeof(struct station_config));
os_memset(&stationConf, 0, sizeof(struct station_config));
os_sprintf(stationConf.ssid, "%s", WIFI_CLIENTSSID);
os_sprintf(stationConf.password, "%s", WIFI_CLIENTPASSWORD);
wifi_station_set_config_current(&stationConf);
wifi_set_sleep_type(NONE_SLEEP_T);
WiFi_StartTimer(1000);
wifi_station_connect();
wifi_station_dhcpc_start();
if (wifi_get_phy_mode() != PHY_MODE_11N) wifi_set_phy_mode(PHY_MODE_11N);//включим протокол физического уровня типа 802.11n, если таковой уже не включен
if(wifi_station_get_auto_connect()==0) wifi_station_set_auto_connect(1);//включим автоматическое соединение с точкой доступа в случае разрыва, если не включено
}
//----------------------------------------------------------------------------------------------------
//системная функция: инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR user_init(void)
{
ReceivedArraySize=0;
StuffingOn=false;
WiFi_State=WIFI_STATE_CONNECTING;
os_delay_us(10000);
UART_Init();
UART_RegisterReceivedFunction(&UART_OnReceived);
UART_RegisterSendDoneFunction(&UART_OnSendDone);
LED_Init();//если поставить перед UART_Init, то не работает
LED_Off();
WiFi_Init();//инициализация WiFi
}
#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__
#include <stdio.h>
enum
{
EVENT_UART_RECEIVED_DATA=0,//пришли данные по UART
EVENT_UART_SEND_DONE,//завершена передача по UART
};
static const size_t EVENT_QUEUE_ID=0;//идентификатор очереди
#endif
#ifndef UART_H
#define UART_H
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <inttypes.h>
#include <stdio.h>
#include <os_type.h>
//****************************************************************************************************
//типы
//****************************************************************************************************
typedef void (*uart_received_func_ptr_t)(const uint8_t*,size_t);//указатель на функцию наличия новых данных
typedef void (*uart_send_done_func_ptr_t)(void);//указатель на функцию завершения передачи данных
//****************************************************************************************************
//макроопределения
//****************************************************************************************************
//****************************************************************************************************
//константы
//****************************************************************************************************
//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
//****************************************************************************************************
//прототипы функций
//****************************************************************************************************
void ICACHE_FLASH_ATTR UART_Init(void);//инициализация
void ICACHE_FLASH_ATTR UART_SendMessage(const char *str);//передать текстовое сообщение
void ICACHE_FLASH_ATTR UART_SendData(const uint8_t* data,size_t size);//передать данные
void ICACHE_FLASH_ATTR UART_RegisterReceivedFunction(uart_received_func_ptr_t func_ptr);//зарегистрировать функцию обратного вызова на приём данных
void ICACHE_FLASH_ATTR UART_RegisterSendDoneFunction(uart_send_done_func_ptr_t func_ptr);//зарегистрировать функцию обратного вызова на завершение передачи данных
#endif
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include "uart.h"
#include "drvuart.h"
#include "user_interface.h"
#include <string.h>
#include <os_type.h>
//****************************************************************************************************
//макроопределения
//****************************************************************************************************
//размер очереди событий UART
#define UART_EVENT_QUEUE_LENGTH 100
//размер буфера приёма данных
#define UART_RECEIVED_BUFFER_SIZE 4096
//****************************************************************************************************
//константы
//****************************************************************************************************
//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
static uart_received_func_ptr_t ReceivedFunctionPtr=NULL;//указатель на функцию обратного вызова по приёму данных
static uart_send_done_func_ptr_t SendDoneFunctionPtr=NULL;//указатель на функцию обратного вызова по завершению передачи данных
static os_event_t EventQueue[UART_EVENT_QUEUE_LENGTH];//очередь событий UART
static uint8_t ReceivedBuffer[UART_RECEIVED_BUFFER_SIZE];//буфер приёма данных UART
//****************************************************************************************************
//прототипы функций
//****************************************************************************************************
static void ICACHE_FLASH_ATTR UART_EventQueueFunction(os_event_t *events);//обработчик очереди сообщений
//****************************************************************************************************
//реализация функций
//****************************************************************************************************
//----------------------------------------------------------------------------------------------------
//инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_Init(void)
{
ReceivedFunctionPtr=NULL;
SendDoneFunctionPtr=NULL;
//uart_init(BIT_RATE_115200);
uart_init(BIT_RATE_921600);
//регистрируем очередь событий
system_os_task(UART_EventQueueFunction,EVENT_QUEUE_ID,EventQueue,UART_EVENT_QUEUE_LENGTH);
}
//----------------------------------------------------------------------------------------------------
//передать текстовое сообщение
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_SendMessage(const char *str)
{
UART_SendData((uint8_t*)str,strlen(str));
}
//----------------------------------------------------------------------------------------------------
//передать данные
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_SendData(const uint8_t* data,size_t size)
{
tx_buff_enq(data,size,true);
}
//----------------------------------------------------------------------------------------------------
//зарегистрировать функцию обратного вызова на приём данных
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_RegisterReceivedFunction(uart_received_func_ptr_t func_ptr)
{
ReceivedFunctionPtr=func_ptr;
}
//----------------------------------------------------------------------------------------------------
//зарегистрировать функцию обратного вызова на завершение передачи данных
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_RegisterSendDoneFunction(uart_send_done_func_ptr_t func_ptr)
{
SendDoneFunctionPtr=func_ptr;
}
//----------------------------------------------------------------------------------------------------
//обработчик очереди сообщений
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_EventQueueFunction(os_event_t *events)
{
if (events==NULL) return;
if (events->sig==EVENT_UART_RECEIVED_DATA)
{
size_t data_length=rx_buff_get_data_len();
if (data_length>UART_RECEIVED_BUFFER_SIZE) data_length=UART_RECEIVED_BUFFER_SIZE;
rx_buff_deq(ReceivedBuffer,data_length);//получаем данные
if (ReceivedFunctionPtr!=NULL) ReceivedFunctionPtr(ReceivedBuffer,data_length);
return;
}
if (events->sig==EVENT_UART_SEND_DONE)
{
if (SendDoneFunctionPtr!=NULL) SendDoneFunctionPtr();
return;
}
}
#ifndef LED_H
#define LED_H
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <os_type.h>
//****************************************************************************************************
//макроопределения
//****************************************************************************************************
//****************************************************************************************************
//константы
//****************************************************************************************************
//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
//****************************************************************************************************
//прототипы функций
//****************************************************************************************************
void ICACHE_FLASH_ATTR LED_Init(void);//инициализация
void ICACHE_FLASH_ATTR LED_On(void);//включить светодиод
void ICACHE_FLASH_ATTR LED_Off(void);//отключить светодиод
#endif
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include "led.h"
#include <gpio.h>
//****************************************************************************************************
//макроопределения
//****************************************************************************************************
#define LED_GPIO 2
#define LED_GPIO_MUX PERIPHS_IO_MUX_GPIO2_U
#define LED_GPIO_FUNC FUNC_GPIO2
//****************************************************************************************************
//константы
//****************************************************************************************************
//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
//****************************************************************************************************
//реализация функций
//****************************************************************************************************
//----------------------------------------------------------------------------------------------------
//инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_Init(void)
{
gpio_init();
PIN_FUNC_SELECT(LED_GPIO_MUX,LED_GPIO_FUNC);
}
//----------------------------------------------------------------------------------------------------
//включить светодиод
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_On(void)
{
GPIO_OUTPUT_SET(LED_GPIO,0);
}
//----------------------------------------------------------------------------------------------------
//отключить светодиод
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_Off(void)
{
GPIO_OUTPUT_SET(LED_GPIO,1);
}
/******************************************************************************
* Copyright 2013-2014 Espressif Systems
*
* FileName: uart_register.h
*
* Description: entry file of user application
*
* Modification history:
* 2015/9/24, v1.0 create this file.
*******************************************************************************/
#ifndef UART_REGISTER_H_
#define UART_REGISTER_H_
#define REG_UART_BASE(i) (0x60000000ul + (i)*0xf00)
//version value:32'h062000
#define UART_FIFO(i) (REG_UART_BASE(i) + 0x0)
#define UART_RXFIFO_RD_BYTE 0x000000FF
#define UART_RXFIFO_RD_BYTE_S 0
#define UART_INT_RAW(i) (REG_UART_BASE(i) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
#define UART_BRK_DET_INT_RAW (BIT(7))
#define UART_CTS_CHG_INT_RAW (BIT(6))
#define UART_DSR_CHG_INT_RAW (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
#define UART_FRM_ERR_INT_RAW (BIT(3))
#define UART_PARITY_ERR_INT_RAW (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
#define UART_INT_ST(i) (REG_UART_BASE(i) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
#define UART_BRK_DET_INT_ST (BIT(7))
#define UART_CTS_CHG_INT_ST (BIT(6))
#define UART_DSR_CHG_INT_ST (BIT(5))
#define UART_RXFIFO_OVF_INT_ST (BIT(4))
#define UART_FRM_ERR_INT_ST (BIT(3))
#define UART_PARITY_ERR_INT_ST (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
#define UART_RXFIFO_FULL_INT_ST (BIT(0))
#define UART_INT_ENA(i) (REG_UART_BASE(i) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_BRK_DET_INT_ENA (BIT(7))
#define UART_CTS_CHG_INT_ENA (BIT(6))
#define UART_DSR_CHG_INT_ENA (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
#define UART_FRM_ERR_INT_ENA (BIT(3))
#define UART_PARITY_ERR_INT_ENA (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_CLR(i) (REG_UART_BASE(i) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
#define UART_BRK_DET_INT_CLR (BIT(7))
#define UART_CTS_CHG_INT_CLR (BIT(6))
#define UART_DSR_CHG_INT_CLR (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
#define UART_FRM_ERR_INT_CLR (BIT(3))
#define UART_PARITY_ERR_INT_CLR (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
#define UART_CLKDIV(i) (REG_UART_BASE(i) + 0x14)
#define UART_CLKDIV_CNT 0x000FFFFF
#define UART_CLKDIV_S 0
#define UART_AUTOBAUD(i) (REG_UART_BASE(i) + 0x18)
#define UART_GLITCH_FILT 0x000000FF
#define UART_GLITCH_FILT_S 8
#define UART_AUTOBAUD_EN (BIT(0))
#define UART_STATUS(i) (REG_UART_BASE(i) + 0x1C)
#define UART_TXD (BIT(31))
#define UART_RTSN (BIT(30))
#define UART_DTRN (BIT(29))
#define UART_TXFIFO_CNT 0x000000FF
#define UART_TXFIFO_CNT_S 16
#define UART_RXD (BIT(15))
#define UART_CTSN (BIT(14))
#define UART_DSRN (BIT(13))
#define UART_RXFIFO_CNT 0x000000FF
#define UART_RXFIFO_CNT_S 0
#define UART_CONF0(i) (REG_UART_BASE(i) + 0x20)
#define UART_DTR_INV (BIT(24))
#define UART_RTS_INV (BIT(23))
#define UART_TXD_INV (BIT(22))
#define UART_DSR_INV (BIT(21))
#define UART_CTS_INV (BIT(20))
#define UART_RXD_INV (BIT(19))
#define UART_TXFIFO_RST (BIT(18))
#define UART_RXFIFO_RST (BIT(17))
#define UART_IRDA_EN (BIT(16))
#define UART_TX_FLOW_EN (BIT(15))
#define UART_LOOPBACK (BIT(14))
#define UART_IRDA_RX_INV (BIT(13))
#define UART_IRDA_TX_INV (BIT(12))
#define UART_IRDA_WCTL (BIT(11))
#define UART_IRDA_TX_EN (BIT(10))
#define UART_IRDA_DPLX (BIT(9))
#define UART_TXD_BRK (BIT(8))
#define UART_SW_DTR (BIT(7))
#define UART_SW_RTS (BIT(6))
#define UART_STOP_BIT_NUM 0x00000003
#define UART_STOP_BIT_NUM_S 4
#define UART_BIT_NUM 0x00000003
#define UART_BIT_NUM_S 2
#define UART_PARITY_EN (BIT(1))
#define UART_PARITY (BIT(0))
#define UART_CONF1(i) (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD 0x0000007F
#define UART_RX_TOUT_THRHD_S 24
#define UART_RX_FLOW_EN (BIT(23))
#define UART_RX_FLOW_THRHD 0x0000007F
#define UART_RX_FLOW_THRHD_S 16
#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S 8
#define UART_RXFIFO_FULL_THRHD 0x0000007F
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_LOWPULSE(i) (REG_UART_BASE(i) + 0x28)
#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S 0
#define UART_HIGHPULSE(i) (REG_UART_BASE(i) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S 0
#define UART_PULSE_NUM(i) (REG_UART_BASE(i) + 0x30)
#define UART_PULSE_NUM_CNT 0x0003FF
#define UART_PULSE_NUM_CNT_S 0
#define UART_DATE(i) (REG_UART_BASE(i) + 0x78)
#define UART_ID(i) (REG_UART_BASE(i) + 0x7C)
#endif // UART_REGISTER_H_INCLUDED
/******************************************************************************
* Copyright 2013-2014 Espressif Systems
*
* FileName: uart.h
*
* Description: entry file of user application
*
* Modification history:
* 2015/9/24, v1.0 create this file.
*******************************************************************************/
#ifndef UART_APP_H
#define UART_APP_H
#include "drvuart_register.h"
#include <eagle_soc.h>
#include <c_types.h>
#define UART0 0
#define UART1 1
typedef enum {
FIVE_BITS = 0x0,
SIX_BITS = 0x1,
SEVEN_BITS = 0x2,
EIGHT_BITS = 0x3
} UartBitsNum4Char;
typedef enum {
ONE_STOP_BIT = 0x1,
ONE_HALF_STOP_BIT = 0x2,
TWO_STOP_BIT = 0x3
} UartStopBitsNum;
typedef enum {
NONE_BITS = 0x2,
ODD_BITS = 1,
EVEN_BITS = 0
} UartParityMode;
typedef enum {
STICK_PARITY_DIS = 0,
STICK_PARITY_EN = 1
} UartExistParity;
typedef enum {
UART_None_Inverse = 0x0,
UART_Rxd_Inverse = UART_RXD_INV,
UART_CTS_Inverse = UART_CTS_INV,
UART_Txd_Inverse = UART_TXD_INV,
UART_RTS_Inverse = UART_RTS_INV,
} UART_LineLevelInverse;
typedef enum {
BIT_RATE_300 = 300,
BIT_RATE_600 = 600,
BIT_RATE_1200 = 1200,
BIT_RATE_2400 = 2400,
BIT_RATE_4800 = 4800,
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400,
BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600,
BIT_RATE_1843200 = 1843200,
BIT_RATE_3686400 = 3686400,
} UartBautRate;
typedef enum {
NONE_CTRL,
HARDWARE_CTRL,
XON_XOFF_CTRL
} UartFlowCtrl;
typedef enum {
USART_HardwareFlowControl_None = 0x0,
USART_HardwareFlowControl_RTS = 0x1,
USART_HardwareFlowControl_CTS = 0x2,
USART_HardwareFlowControl_CTS_RTS = 0x3
} UART_HwFlowCtrl;
typedef enum {
EMPTY,
UNDER_WRITE,
WRITE_OVER
} RcvMsgBuffState;
typedef struct {
uint32 RcvBuffSize;
uint8 *pRcvMsgBuff;
uint8 *pWritePos;
uint8 *pReadPos;
uint8 TrigLvl; //JLU: may need to pad
RcvMsgBuffState BuffState;
} RcvMsgBuff;
typedef struct {
uint32 TrxBuffSize;
uint8 *pTrxBuff;
} TrxMsgBuff;
typedef enum {
BAUD_RATE_DET,
WAIT_SYNC_FRM,
SRCH_MSG_HEAD,
RCV_MSG_BODY,
RCV_ESC_CHAR,
} RcvMsgState;
typedef struct {
UartBautRate baut_rate;
UartBitsNum4Char data_bits;
UartExistParity exist_parity;
UartParityMode parity; // chip size in byte
UartStopBitsNum stop_bits;
UartFlowCtrl flow_ctrl;
RcvMsgBuff rcv_buff;
TrxMsgBuff trx_buff;
RcvMsgState rcv_state;
int received;
int buff_uart_no; //indicate which uart use tx/rx buffer
} UartDevice;
void uart_init(UartBautRate uart0_br);
///////////////////////////////////////
#define UART_FIFO_LEN 128 //define the tx fifo length
//
#define UART_TX_EMPTY_THRESH_VAL 0x10
#define UART_TX_BUFFER_SIZE 8192
#define URAT_TX_LOWER_SIZE 1024*7
#define URAT_TX_UPPER_SIZE 8000*1
#define UART_RX_BUFFER_SIZE (10*1024) //201
//#define UART_TX_DEBUG
#define DBG(...)
#define DBG1(...) //uart1_sendStr_no_wait
#define DBG2(...) //os_printf
struct UartBuffer {
uint16 UartBuffSize;
uint8 *pUartBuff;
uint8 *pInPos;
uint8 *pOutPos;
STATUS BuffState;
uint16 Space; //remanent space of the buffer
// uint8 TcpControl;
struct UartBuffer *nextBuff;
};
struct UartRxBuff {
uint32 UartRxBuffSize;
uint8 *pUartRxBuff;
uint8 *pWritePos;
uint8 *pReadPos;
STATUS RxBuffState;
uint32 Space; //remanent space of the buffer
} ;
void tx_buff_enq(const char *pdata, uint16 data_len, bool force);
uint16 rx_buff_deq(char *pdata, uint16 data_len);
//==============================================
#define FUNC_UART0_CTS 4
#define UART_LINE_INV_MASK (0x3f<<19)
#endif
/******************************************************************************
* Copyright 2013-2014 Espressif Systems
*
* FileName: uart.c
*
* Description: entry file of user application
*
* Modification history:
* 2015/9/24, v1.0 create this file.
*******************************************************************************/
#include <ets_sys.h>
#include <osapi.h>
#include <mem.h>
#include "drvuart.h"
#include "drvuart_register.h"
#include "user_interface.h"
#include <espconn.h>
#define FUNC_U1TXD_BK 2
#define FUNC_U0CTS 4
extern UartDevice UartDev;
static struct UartBuffer *pTxBuffer = NULL;
static struct UartBuffer *pRxBuffer = NULL;
LOCAL void uart0_rx_intr_handler(void *para);
void uart1_sendStr_no_wait(const char *str);
struct UartBuffer * Uart_Buf_Init(uint32 buf_size);
void rx_buff_enq(void);
void tx_start_uart_buffer(uint8 uart_no);
void uart_rx_intr_disable(uint8 uart_no);
void uart_rx_intr_enable(uint8 uart_no);
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
* UART1 just used for debug output
* Parameters : uart_no, use UART0 or UART1 defined ahead
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart_config(uint8 uart_no)
{
if (uart_no == UART1) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
} else {
/* rcv_buff size if 0x100 */
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);
PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTCK_U);
}
uart_div_modify(uart_no, (uint16)(UART_CLK_FREQ / (uint32)(UartDev.baut_rate)));
WRITE_PERI_REG(UART_CONF0(uart_no), (uint32)UartDev.exist_parity
| (uint32)UartDev.parity
| (((uint8)UartDev.stop_bits) << UART_STOP_BIT_NUM_S)
| (((uint8)UartDev.data_bits) << UART_BIT_NUM_S));
//clear rx and tx fifo,not ready
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
if (uart_no == UART0) {
//set rx fifo trigger
WRITE_PERI_REG(UART_CONF1(uart_no),
((100 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
UART_RX_FLOW_EN |
(0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
UART_RX_TOUT_EN |
((0x10 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S)); //wjl
//SET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN); //add this sentense to add a tx flow control via MTCK( CTS )
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
UART_FRM_ERR_INT_ENA);
} else {
WRITE_PERI_REG(UART_CONF1(uart_no),
((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
}
//clear all interrupt
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
//enable rx_interrupt
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_OVF_INT_ENA);
}
/******************************************************************************
* FunctionName : uart1_tx_one_char
* Description : Internal used function
* Use uart1 interface to transfer one char
* Parameters : uint8 TxChar - character to tx
* Returns : OK
*******************************************************************************/
STATUS
uart_tx_one_char(uint8 uart, uint8 TxChar)
{
for(;;) {
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
* Do some special deal while tx char is '\r' or '\n'
* Parameters : char c - character to tx
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart1_write_char(char c)
{
if (c == '\n') {
(void)uart_tx_one_char(UART1, '\r');
(void)uart_tx_one_char(UART1, '\n');
} else if (c == '\r') {
} else {
(void)uart_tx_one_char(UART1, (uint8)c);
}
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
* UART0 interrupt handler, add self handle code inside
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
* Returns : NONE
*******************************************************************************/
LOCAL void
uart0_rx_intr_handler(void *para)
{
uint8 uart_no = UART0;
if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
uart1_sendStr_no_wait("FRM_ERR\r\n");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
}
if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
uart_rx_intr_disable(uart_no);
rx_buff_enq();
} else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
uart_rx_intr_disable(uart_no);
rx_buff_enq();
} else if (UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)) {
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_TXFIFO_EMPTY_INT_ENA);
tx_start_uart_buffer(uart_no);
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
} else if (UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)) {
uart1_sendStr_no_wait("RX OVF!\r\n");
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
}
}
/******************************************************************************
* FunctionName : uart_init
* Description : user interface for init uart
* Parameters : UartBautRate uart0_br - uart0 bautrate
* UartBautRate uart1_br - uart1 bautrate
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br)
{
UartDev.baut_rate = uart0_br;
uart_config(UART0);
UartDev.baut_rate = BIT_RATE_115200;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
os_install_putc1(uart1_write_char);
pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
pRxBuffer = Uart_Buf_Init(UART_RX_BUFFER_SIZE);
}
/******************************************************************************
* FunctionName : uart_tx_one_char_no_wait
* Description : uart tx a single char without waiting for fifo
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
STATUS
uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
{
uint8 fifo_cnt = ((READ_PERI_REG(UART_STATUS(uart)) >> UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
if (fifo_cnt < 126) {
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
}
return OK;
}
/******************************************************************************
* FunctionName : uart1_sendStr_no_wait
* Description : uart tx a string without waiting for every char, used for print debug info which can be lost
* Parameters : const char *str - string to be sent
* Returns : NONE
*******************************************************************************/
void
uart1_sendStr_no_wait(const char *str)
{
if(str == NULL) {
return;
}
while (*str) {
(void)uart_tx_one_char_no_wait(UART1, (uint8)*str);
str++;
}
}
/******************************************************************************
* FunctionName : Uart_Buf_Init
* Description : tx buffer enqueue: fill a first linked buffer
* Parameters : char *pdata - data point to be enqueue
* Returns : NONE
*******************************************************************************/
struct UartBuffer *ICACHE_FLASH_ATTR
Uart_Buf_Init(uint32 buf_size)
{
uint32 heap_size = system_get_free_heap_size();
if(buf_size > 65535) { // now not support
DBG1("no buf for uart\n\r");
return NULL;
}
if (heap_size <= buf_size) {
DBG1("no buf for uart\n\r");
return NULL;
} else {
DBG("test heap size: %d\n\r", heap_size);
struct UartBuffer *pBuff = (struct UartBuffer *)os_malloc((uint32)sizeof(struct UartBuffer));
pBuff->UartBuffSize = (uint16)buf_size; // THIS OK
pBuff->pUartBuff = (uint8 *)os_malloc(pBuff->UartBuffSize);
pBuff->pInPos = pBuff->pUartBuff;
pBuff->pOutPos = pBuff->pUartBuff;
pBuff->Space = pBuff->UartBuffSize;
pBuff->BuffState = OK;
pBuff->nextBuff = NULL;
// pBuff->TcpControl = RUN;
return pBuff;
}
}
LOCAL void
Uart_Buf_Cpy(struct UartBuffer *pCur, const char *pdata , uint16 data_len)
{
if ((pCur == NULL) || (pdata == NULL) || (data_len == 0)) {
return ;
}
uint16 tail_len = (uint16)(pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos); // THIS OK
if (tail_len >= data_len) { //do not need to loop back the queue
os_memcpy(pCur->pInPos , pdata , data_len);
pCur->pInPos += (data_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= data_len;
} else {
os_memcpy(pCur->pInPos, pdata, tail_len);
pCur->pInPos += (tail_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= tail_len;
os_memcpy(pCur->pInPos, pdata + tail_len , data_len - tail_len);
pCur->pInPos += (data_len - tail_len);
pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
pCur->Space -= (data_len - tail_len);
}
}
/******************************************************************************
* FunctionName : uart_buf_free
* Description : deinit of the tx buffer
* Parameters : struct UartBuffer* pTxBuff - tx buffer struct pointer
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart_buf_free(struct UartBuffer *pBuff)
{
if(pBuff != NULL) {
if(pBuff->pUartBuff != NULL) {
os_free(pBuff->pUartBuff);
}
os_free(pBuff);
}
}
uint16 ICACHE_FLASH_ATTR
rx_buff_get_data_len(void)
{
uint16 buf_len = pRxBuffer->UartBuffSize - pRxBuffer->Space;
return buf_len;
}
uint16 ICACHE_FLASH_ATTR
rx_buff_deq(char *pdata, uint16 data_len)
{
uint16 len_tmp = 0;
uint16 buf_len = pRxBuffer->UartBuffSize - pRxBuffer->Space;
uint16 tail_len = (uint16)(pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize - pRxBuffer->pOutPos); // THIS OK
len_tmp = ((data_len > buf_len) ? buf_len : data_len);
if (pRxBuffer->pOutPos <= pRxBuffer->pInPos) {
if(pdata != NULL) {
os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
}
pRxBuffer->pOutPos += len_tmp;
pRxBuffer->Space += len_tmp;
} else {
if (len_tmp > tail_len) {
if(pdata != NULL) {
os_memcpy(pdata, pRxBuffer->pOutPos, tail_len);
}
pRxBuffer->pOutPos += tail_len;
pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
pRxBuffer->Space += tail_len;
if(pdata != NULL) {
os_memcpy(pdata + tail_len , pRxBuffer->pOutPos, len_tmp - tail_len);
}
pRxBuffer->pOutPos += (len_tmp - tail_len);
pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
pRxBuffer->Space += (len_tmp - tail_len);
} else {
if(pdata != NULL) {
os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
}
pRxBuffer->pOutPos += len_tmp;
pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
pRxBuffer->Space += len_tmp;
}
}
// os_printf("recv:%d\r\n",pRxBuffer->Space);
return len_tmp;
}
void
rx_buff_enq(void)
{
uint8 fifo_len = 0, buf_idx = 0,loop;
ETSParam par = 0;
uint8 fifo_data;
uint8* tail = (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize);
fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
if(fifo_len > pRxBuffer->Space) {
buf_idx = pRxBuffer->Space;
} else {
buf_idx = fifo_len;
}
loop = buf_idx;
while (loop--) {
*(pRxBuffer->pInPos++) = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
if (pRxBuffer->pInPos == tail) {
pRxBuffer->pInPos = pRxBuffer->pUartBuff;
}
}
fifo_len -= buf_idx;
while (fifo_len--) {
fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; // discard data
}
pRxBuffer->Space -= buf_idx ;
par = buf_idx;
if(system_os_post(EVENT_QUEUE_ID,(ETSSignal)EVENT_UART_RECEIVED_DATA, par) != TRUE) {
os_printf("post fail!!!\n\r");
}
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
uart_rx_intr_enable(UART0);
}
void ICACHE_FLASH_ATTR
tx_buff_enq(const char *pdata, uint16 data_len, bool force)
{
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
//DBG2("len:%d\n\r",data_len);
if(pdata != NULL) {
if (pTxBuffer == NULL) {
DBG1("\n\rnull, create buffer struct\n\r");
pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
if (pTxBuffer != NULL) {
Uart_Buf_Cpy(pTxBuffer , pdata, data_len);
} else {
DBG1("uart tx MALLOC no buf \n\r");
}
} else {
if (data_len <= pTxBuffer->Space) {
Uart_Buf_Cpy(pTxBuffer , pdata, data_len);
} else if (force) {
for(;;) {
tx_start_uart_buffer(UART0);
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
if (data_len <= pTxBuffer->Space) {
Uart_Buf_Cpy(pTxBuffer , pdata, data_len);
break;
}
ets_delay_us(70);
WRITE_PERI_REG(0X60000914, 0x73);
};
} else {
DBG1("UART TX BUF FULL!!!!\n\r");
}
}
if ((pTxBuffer != NULL) && (pTxBuffer->Space <= URAT_TX_LOWER_SIZE))
{
//set_tcp_block();
}
}
SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
}
//--------------------------------
LOCAL void tx_fifo_insert(struct UartBuffer *pTxBuff, uint8 data_len, uint8 uart_no)
{
uint8 i;
if(pTxBuff == NULL) {
return;
}
for (i = 0; i < data_len; i++) {
WRITE_PERI_REG(UART_FIFO(uart_no) , *(pTxBuff->pOutPos++));
if (pTxBuff->pOutPos == (pTxBuff->pUartBuff + pTxBuff->UartBuffSize)) {
pTxBuff->pOutPos = pTxBuff->pUartBuff;
}
}
pTxBuff->pOutPos = (pTxBuff->pUartBuff + (pTxBuff->pOutPos - pTxBuff->pUartBuff) % pTxBuff->UartBuffSize);
pTxBuff->Space += data_len;
}
/******************************************************************************
* FunctionName : tx_start_uart_buffer
* Description : get data from the tx buffer and fill the uart tx fifo, co-work with the uart fifo empty interrupt
* Parameters : uint8 uart_no - uart port num
* Returns : NONE
*******************************************************************************/
void tx_start_uart_buffer(uint8 uart_no)
{
uint8 tx_fifo_len = (READ_PERI_REG(UART_STATUS(uart_no)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT;
uint8 fifo_remain = UART_FIFO_LEN - tx_fifo_len ;
uint8 len_tmp;
uint32 data_len;
if (pTxBuffer) {
data_len = (pTxBuffer->UartBuffSize - pTxBuffer->Space);
if (data_len > fifo_remain) {
len_tmp = fifo_remain;
tx_fifo_insert(pTxBuffer, len_tmp, uart_no);
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
} else {
len_tmp = (uint8)data_len; // THIS OK
tx_fifo_insert(pTxBuffer, len_tmp, uart_no);
}
if (pTxBuffer->Space >= URAT_TX_UPPER_SIZE) {
(void)system_os_post(EVENT_QUEUE_ID,(ETSSignal)EVENT_UART_SEND_DONE,(ETSParam)0);
}
}
}
void uart_rx_intr_disable(uint8 uart_no)
{
CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}
void uart_rx_intr_enable(uint8 uart_no)
{
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}
//========================================================
Используя функции Lua C API, предназначенные для манипуляции с данными получаемыми/передаваемыми из внешних библиотек, теоретически возможно все это серьезно заоптимизировать. Но это (на мой взгляд) подобно сексу в гамаке стоя. Ибо зачем так извращаться, когда можно просто написать нужное на C/C++.
Насколько я помню работу с Lua C API, написание сишной библиотеки для использования человеческих сишных массивов из lua займет строк 20-50 на С. Там всё очень близко к С. Разве это не так?
Я имел в виду не написание C-библиотеки (подозреваю, что для NodeMCU это не невозможно, но несколько сложнее того, ради чего используют NodeMCU), а использования функционала C API для более эффективного преобразования структур данных: сначала преобразуем входной "массив" в userdata, как будто бы мы хотели отправлять его в C, затем эту userdata преобразуем в string. Скорее всего это получится сделать гораздо эффективнее, чем прикладными методами.
А что будет с картинкой, если пи принять равным 4?
На русском… сомневаюсь.
Смотрите в сторону FSMC функционала. Как раз для работы с SRAM и для вывода на экран в через параллельную шину.
Я такое делал.
https://github.com/mmMikeKn/CNC/tree/master/src/liblcd
То, что вы описали про АЦП, память и дисплей похоже на цифровой осциллограф, но тут хорошо бы начать с приблизительной оценки — а потянет ли контроллер столько? Что он с этими данными делать будет? Если просто отобразить на дисплее, так там 32 кБ не нужно, хватит тех же 320 байт. Ну пусть 640 если по 2 байта на отсчет. Если передавать в компьютер, то по какому интерфейсу? USB тоже не потянет.
Да даже если АЦП будет выдавать по 20 мегасемплов в секунду, сколько тактов у контроллера уйдет чтобы их забрать и хотя бы сложить в память, не говоря уж об обработке?
Эпично.
Я правильно понимаю, что у вас сцена рисуется построчно, по 240 раз на кадр?
А вы не хотите заморочиться и далее, релиазовав поддержку чтения формата Binary GLTF? Этот формат более дружелюбен к современным графическим api, чем obj.
На счет glTF, то до вашего вопроса даже не знал что это такое :) Как бы то ни было, развивать именно трехмерку на stm32 я не планирую. Но не исключено, что воспользуюсь в более «взрослой» графике. Спасибо что упомянули про такой формат.
Этот формат дружелюбен к современным графическим api
Он дружелюбен (прибит гвоздями) к OpenGL, а не к современным графическим API. JSON-часть этого формата не выглядит хорошим решением для микроконтроллеров. Если выкинуть JSON, то остаётся просто блоб, который загружать даже проще, чем Wavefront OBJ. Достаточно memcpy или аналога, идентичного натуральному.
OpenGL к современным графическим API я не отношу в силу того, что архитектура OpenGL идёт в разрез с тем, как устроенны современные GPU.
Спасибо!!! Хоть немного людей в этом мире еще не превратились в хомячков…
Хороший и показательный пример использования ресурсов.
От себя добавлю:
По сравнению с AVR характеристики камня довольно приличные: 72 МГц тактовой (на практике можно разогнать до 100 МГц, а то и больше, но только на свой страх и риск!), 20 кБ оперативки и 64 кБ флеша.
Разгоняется до 144 МГц (из периферии становится недоступным только USB), в работе на такой частоте — чуть теплый.
А флеша у этого чипа 128кб. :) (Для демки — самое то).
Z-координату вообще можно вытянуть из уравнения плоскости:
Z = (D — x*nx — y*ny)/nz,
D = px*nx + py*ny + pz*nz,
где nx,ny,nz — нормаль
pz,py,pz — опорная точка (скажем, любая вершина), но она пересчитывается в одну скалярную константу D
x,y — координаты на плоскости, z — глубина
— Но в целом необходимости в этом немного: в моем варианте память контроллера кончилась ненамного позже запаса быстродействия, выигрыш будет хорошо если в 2 раза на сложных модельках
не подскажите как дать второе дыхание старому китайскому планшету? к примеру - как использовать экран с тачскрином в связке с малинкой
Трехмерная графика на STM32F103