Сервер на Iskra js

Тема в разделе "Iskra JS, Espruino, Йодо", создана пользователем VOL_IN, 30 дек 2017.

  1. sys

    sys Злобный Буратино Модератор

    :) оптимизация это хорошо (как минимум интересно поиграть)
    по поводу скорости SPI могу процитировать референс http://www.farnell.com/datasheets/2307757.pdf
    с MODE 0 и 3 тоже не играл...

    P.S.: прям интрига... что же там за код? :)
     
    Последнее редактирование: 6 янв 2018
    VOL_IN нравится это.
  2. sys

    sys Злобный Буратино Модератор

    скажу честно, для аналога не встречал
     
  3. VOL_IN

    VOL_IN Нерд

    Ну что вы?! На данный момент код почти клон вашего, просто подумал что не стоит плодить копипастовые посты. Итоговый вариант выложу конечно.
    Т.е. чтобы Ethernet shield работал шустрее надо его подключить не к SPI2, а к SPI1. И как "бонус" лишиться трех аналоговых входов. Прям скажу не фонтан...:(
     
  4. sys

    sys Злобный Буратино Модератор

    не надо к SPI1 :)
    Могу сказать по экспериментам со скоростью. Пока что мне удалось выжать из связки искра + w5500 в роли сервера максимум 187 Кб/с при установленном SPI2 битрейте 21000000. При 3200000 максимум 125 Кб/с. При этом надо быть очень аккуратным с объемами передаваемых данных, т.к. Искра легко подвисает...
    Так что SPI1 не спасет ...
    Тестил этим кодом
    Код (Javascript):
    SPI2.setup({baud: 21000000, mosi: B15, miso: B14, sck: B13, mode: 3});
    var ethernet = require('WIZnet').connect(SPI2, P10);
    ethernet.setIP();
    print(ethernet.getIP());

    var limint = 1;
    var intNum = 0;

    var server = require("net").createServer(function(c) {
      var mon = {};
      c.write('input interval in ms: ');
      c.on('data', function(data) {
      data = data.trim();
      if(data===""){
      mon.emit('stop');
      }
      else if(data==="exit"){
      mon.emit('exit');
      }
      else if(!isNaN(data)){
      mon.emit('test', data);
      }
      else{
      mon.emit('error');
      }
      });
      c.on('end',function(){
      clearInterval(intNum);
      });
      mon.on('stop',function(){
      clearInterval(intNum);
      c.write('input interval in ms: ');
      });
      mon.on('exit',function(){ c.end(); });
      mon.on('error', function(){
      c.write('error\n');
      });
      mon.on('test',function(data){
      if(data<limint) data = limint;
      intNum = setInterval(function(){
      c.write('00000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999');
      },data);
      });
    });

    server.listen(8000);
     
    Причем, если данные подносить следующим способом:
    Код (Javascript):
    c.write('00000000000000000000000000000000000000000000000000');
    c.write('11111111111111111111111111111111111111111111111111');
    c.write('22222222222222222222222222222222222222222222222222');
    c.write('33333333333333333333333333333333333333333333333333');
    c.write('44444444444444444444444444444444444444444444444444');
    c.write('55555555555555555555555555555555555555555555555555');
    c.write('66666666666666666666666666666666666666666666666666');
    c.write('77777777777777777777777777777777777777777777777777');
    c.write('88888888888888888888888888888888888888888888888888');
    c.write('99999999999999999999999999999999999999999999999999');
     
    Скорость упадет до 128 Кб/с (при 21000000) и 94 Кб/с (при 3200000).

    Проверял на минимально возможных интервалах 2-4 мс (меньше 4 мс интервалы нестабильны и имеют реальный промежуток 2-3 мс).
    При этом если добавить к выводимой строке еще чуток '101010101010101010101010101010101010101010101010', то при интервале 4 мс мы получим захлебывающуюся Искру - начальная скорость 60-100 Кб/с резко начинает падать и далее либо, если успеет, разорвется соединение, либо зависон. При еще большей объеме данных - просто зависон :)

    P.S. Кб - килобайт
     
    Последнее редактирование: 6 янв 2018
    ИгорьК нравится это.
  5. sys

    sys Злобный Буратино Модератор

    Перечитал свой пост выше и как-то показался он мне недосказанным про объемы... Чтобы Искра не давилась и не висла большие объемы передаются с помощью обработчика события .on('drain',...) http://www.espruino.com/Reference#l_Socket_drain

    Пример есть в разделе "Transferring large amounts of data" http://www.espruino.com/Internet ...
    Но скорости не такие большие. Если брать тот пример с циклом до 10, то скорость в районе 20 Кб/с у меня получалась... Если же сделать
    Код (Javascript):
    res.on('drain',function() {
           res.write(history[n++]+",");
        if (n>=history.length) res.end(" ];");
      });
    то скорость разгонялась до 60 Кб/с
    Вот как-то так...
     
    ИгорьК нравится это.
  6. VOL_IN

    VOL_IN Нерд

    Пробую подключить ethernet shield к SPI1, не получается, код не работает. Просто решил попробовать. Сейчас скорость у меня примерно 16 килобайт в секунду. Т.е. данные с 12 аналоговых входов + время собираю в массив Uint16Array, далее он преобразуется в строку (socket.write("массив"), ну или socket.write("массив".join(','))), это если данные преобразовывать в число от 0 до 4095, если собирать числа от 0 до 1 в Float32Array, то скорость выше, порядка 43 кб/с по умолчанию с запятыми в качестве разделителя. О 150 - 100 кб/с и речи не идет, или я где то сильно туплю, хотя время уходит на получение данных с АЦП поочередно.
    А вот тут: http://www.farnell.com/datasheets/2307757.pdf на стр. 134 есть табличные данные о быстродействии АЦП при 12,10,8,6 битах, а как "сказать" Iskre чтоб АЦП работал на 8 битах, и выдавал количество полок АЦП как в Ардуино, а не некое число от 0 до 1, мне этого хватит, но быстродействие еще немного увеличится? 'drain' не пробовал
     
    Последнее редактирование: 7 янв 2018
  7. sys

    sys Злобный Буратино Модератор

    А смысл? У Искры работает интерпретатор, который требует определенного кол-ва времени на интерпретацию и исполнение мк ваших задумок. Espruino не для суперскоростей... :)
     
  8. VOL_IN

    VOL_IN Нерд

    Вот промежуточный код, считаю что можно еще ускорить. Посмотрите, надеюсь на ваш опыт оптимизации, может я накосячил и не вижу, может еще идеи появятся.
    Код (Javascript):
    SPI2.setup({baud: /*3200000*/ 21000000, mosi: B15, miso: B14, sck: B13});
    var ethernet = require('WIZnet').connect(SPI2, P10);
    ethernet.setIP();
    print(ethernet.getIP());
    const port = 80;
    var MA = new Float32Array(13);
    var Ar = analogRead;

    pinMode(P2,"analog");pinMode(P3,"analog");pinMode(P4,"analog");pinMode(P5,"analog");
    pinMode(P6,"analog");pinMode(P7,"analog");pinMode(A0,"analog");pinMode(A1,"analog");
    pinMode(A2,"analog");pinMode(A3,"analog");pinMode(A4,"analog");pinMode(A5,"analog");

    function getData()
    {"compiled";
      MA[0]=getTime().toFixed(0);
      MA[1]=Ar(A0);
      MA[2]=Ar(A1);
      MA[3]=Ar(A2);
      MA[4]=Ar(A3);
      MA[5]=Ar(A4);
      MA[6]=Ar(A5);
      MA[7]=Ar(P2);
      MA[8]=Ar(P3);
      MA[9]=Ar(P4);
      MA[10]=Ar(P5);
      MA[11]=Ar(P6);
      MA[12]=Ar(P7);
      return MA;
    }

    var buttonReset = require('@amperka/button').connect(P13);
    buttonReset.on('hold', function(){reset();});

    var dateCurrent = new Date();
    var interval = 0;

    var server = require("net").createServer(function(socketClient)
      {
        var socketServer = {};
        console.log("-> Server: client conected");

        socketClient.on('data', function(data){
        var str = "";
        for (var i = 4; i < data.length; i = i + 2) {str += data[i + 1].toString(10);}
        console.log("-> Client sent: ", str);
        var command1 = parseInt(str);

        if (command1 === 900){socketServer.emit('exit');}
        if (command1 === 2)  {socketServer.emit('getSycleData'); }
        if (command1 === 800){socketServer.emit('stop');}
        if (isNaN(command1)) {socketServer.emit('error');}
        });
        socketServer.on('exit', function(){console.log('-> Server: client disconected'); socketClient.end();});
        socketServer.on('error', function(){console.log('-> Server: error command');});
        socketServer.on('getSycleData', function()
                                         {
                                            "compiled";
                                            console.log('-> Server: getting sycle data');
                                            interval = setInterval(function(){socketClient.write(getData());},1);
                                         }
                       );
        socketServer.on('stop', function(){clearInterval(interval);console.log('-> Server: stop getting data');});
      });
      server.listen(port);
     
    Клиент получает около 270 сообщений в секунду, емкость каждой (если каждый символ равен 1 байту) около 160 байт. Получаем примерно 43 кб/с.
     
    sys нравится это.
  9. sys

    sys Злобный Буратино Модератор

    Вряд ли я смогу соптимизировать более чем есть :)
     
    VOL_IN нравится это.
  10. VOL_IN

    VOL_IN Нерд

    "не верю!!!", по поводу АЦП - 8 бит, есть соображения?
     
  11. sys

    sys Злобный Буратино Модератор

    ну ладно, ладно... но Вы сами напросились :) Сделайте одновременно 2-3 одинаковых интервальных функции, типа
    Код (Javascript):
    socketServer.on('getSycleData', function()
                                         {
                                            "compiled"; // не сработает
                                            console.log('-> Server: getting sycle data');
                                            interval1 = setInterval(function(){socketClient.write(getData());},1);
                                            interval2 = setInterval(function(){socketClient.write(getData());},1);
                                            interval3 = setInterval(function(){socketClient.write(getData());},1);// если захлебывается - убераем
                                         }
                       );
    но тогда и
    Код (Javascript):
    socketServer.on('stop', function(){clearInterval(interval1);clearInterval(interval2);clearInterval(interval3);console.log('-> Server: stop getting data');});
      });
    ...может повезёт и заработает... Возможно придется поиграть со временем интервала

    И еще... я не уверен, что "compiled" сработает в callback обработчика

    По поводу ADC - никогда не лез в дебри... Довольствовался https://www.espruino.com/ADC
     
    Последнее редактирование: 8 янв 2018
  12. VOL_IN

    VOL_IN Нерд

    При добавлении второй интервальной функции прирост составляет 10 сообщений в секунду
    , при добавлении третьей прирост 5. Т.е. прирост есть, но небольшой. Все таки наверное надо оптимизировать analogRead(), проредить АЦП, 8 бит мне вполне хватит... Амперка выручай!!! Как поменять разрешение АЦП???
     
    Последнее редактирование: 8 янв 2018
  13. sys

    sys Злобный Буратино Модератор

    Пока Амперка на отдыхе посмею теоретически предположить, что поменять можно внесением изменений в код прошивки Espruino и ее пересборки...
    Возможно если поменяете в строке 313 файла https://github.com/amperka/Espruino/blob/iskrajs/targetlibs/stm32f4/lib/stm32f4xx_adc.c:
    Код (C++):
     ADC_InitStruct->ADC_Resolution = ADC_Resolution_12b;
    на
    Код (C++):
     ADC_InitStruct->ADC_Resolution = ADC_Resolution_8b;
    пересоберёте и прошьете, то всё будет :)

    для затравки http://forum.amperka.ru/threads/Сборка-прошивки-iskrajs-в-windows-10.8956/

    UPD: Возможно есть вариант поиграть с регистрами https://www.espruino.com/STM32+Peripherals, но тут надо четко понимать что делаешь.
     
    Последнее редактирование: 8 янв 2018
  14. acos

    acos Официальный гик Администратор

    Ускорение АЦП возможно, в принципе. Но это налагает некоторые ограничения на ваш источник измеряемого напряжения. Во первых он должен быть мощным, способным отдавать достаточно большоой ток. Тоесть потенциометр на 10 кОм не пойдёт. Тут надо зарядить конденсатор АЦП. Можно сделать это за 7 с половиной циклов тактирования блока АЦП. А можно за .239,5 циклов. Если источник не умеет отдавать большой ток, то вы увидете, что показания АЦП на разных каналах у вас начинают зависеть друг от друга. Крутите одну ручку, а изменяют значение напряжения на всех каналах сразу.

    Вот тут происходит выбор того самого времени семплирования https://github.com/espruino/Espruino/blob/master/targets/stm32/jshardware.c

    Код (C++):
    #if defined(STM32F2) || defined(STM32F4)
      uint8_t sampleTime = fastConversion ? ADC_SampleTime_3Cycles : ADC_SampleTime_480Cycles;
    #elif defined(STM32F3)
      uint8_t sampleTime = fastConversion ? ADC_SampleTime_7Cycles5 : ADC_SampleTime_601Cycles5;
    #else
      uint8_t sampleTime = fastConversion ? ADC_SampleTime_7Cycles5 : ADC_SampleTime_239Cycles5;
    #endif
      ADC_RegularChannelConfig(ADCx, stmADCChannel(analog), 1, sampleTime);
    в цункции
    Код (C++):
    static NO_INLINE int jshAnalogRead(JsvPinInfoAnalog analog, bool fastConversion) {
    где-то дальше она должна вызываться для возвращения собственно АЦП.
    Нашёл:
    Код (C++):
    JsVarFloat jshPinAnalog(Pin pin) {
      if (pin >= JSH_PIN_COUNT /* inc PIN_UNDEFINED */ || pinInfo[pin].analog==JSH_ANALOG_NONE) {
        jshPrintCapablePins(pin, "Analog Input", 0,0,0,0, true);
        return 0;
      }
      if (!jshGetPinStateIsManual(pin))
        jshPinSetState(pin, JSHPINSTATE_ADC_IN);

      return jshAnalogRead(pinInfo[pin].analog, false) / (JsVarFloat)65535;
    }

    /// Returns a quickly-read analog value in the range 0-65535
    int jshPinAnalogFast(Pin pin) {
      return jshAnalogRead(pinInfo[pin].analog, true);
    }
    Вот если при analogRead() вместо jshPinAnalog использовать jshPinAnalogFast, должно работать быстрее... Только я пока не нашёл где это надо заменить)
     
    VOL_IN и sys нравится это.
  15. VOL_IN

    VOL_IN Нерд

    Увы, мощность источника сигнала микровольты усиленные операционными усилителями. Дальше усиливать не вариант, шумы полезут, да и слишком замысловатая штуковина вырисовывается...
    Огромное спасибо всем участникам темы. Принял решение временно прекратить проработку сервера на JS, вернулся на Arduino Mega 2560. Javascript - интереснейшая штука, требует глубокого изучения. С++ для меня, на данном этапе жизни, удобней что-ли, в плане покупка Arduino Due(есть возможность менять разрядность АЦП, тут то, наверно))), немного и ускорю).

    Однако стоит отметить что поставленная задача реализована. Сервер на базе Iskra JS создан, есть возможность управления сервером, остальное - это полет фантазии))). Есть необходимые для изучения примеры программного кода и многие смогут реализовать свои решения. Еще раз спасибо и удачи!
     
  16. acos

    acos Официальный гик Администратор

    Это и есть мощный источник. Операционник может отдать большой ток. Можете смело пользоваться быстрым ацп
     
  17. VOL_IN

    VOL_IN Нерд

    Эх, интрига, надо ток померить после операционников... Пробовал быстрый АЦП на Arduino Mega вместе с доработкой кода. Работало плохо, показания нескольких аналоговых входов были одинаковыми, т.е. отображали один и тот же процесс. На этом я вернул обычную "скорость" АЦП, а потом нашел ошибку в коде (накосячил с оптимизацией). Вот точно, надо теперь попробовать "быстрый" АЦП, что-то я заработался и забыл. Вот бы разрядность АЦП еще снизить до 8 бит, мне больше не надо. А смена разрядности АЦП из IDE реализуется на Arduino Due и на Zero по моему. Может есть конечно "хитрые способы" сменить разрядность АЦП на Mega, но я их не знаю. А Iskr-у JS я решил пока отложить на время, надо книжки почитать в свободное время, а то в день по нескольку раз приходится восстанавливать ее работоспособность. "Закирпичить" ее вообще не проблема, надо научиться правильному коду.

    P.S. А какой должен быть ток? Чтобы АЦП успевал работать? И как определить что тока не хватает, т.е. АЦП будет "недобирать нужный уровень". Или вообще работать не будет))). С понедельника попробую, отпишусь...
     
    Последнее редактирование: 19 янв 2018