admin

ЭМУЛЯТОР С ВЕКТОРНОЙ ГРАФИКОЙ



Эмулируемая реальная система с модулем управления на базе ETRX

Расширенный векторной графикой отображения управляемых объектов эмулятор ETRX с инсталлированными командами старта и реверсного хода паровоза.

ДЛЯ СТАРТА АНИМАЦИИ НЕОБХОДИМО:
ИНИЦИАЛИЗИРОВАТЬ КООРДИНАТОР
AT+EN
ОБРАЗОВАТЬ СЕТЬ
AT+SN
КОМАНДА ВПЕРЕД
ATREMS:E627,18=00000040
КОМАНДА НАЗАД
ATREMS:E627,18=00000080

Наскриншотить реакцию эмулятора при подаче команды ВПЕРЕД до инициализации сети ETRX и после.


<? /* КОД ЭМУЛЯТОРА С АНИМАЦИЕЙ */ ?>
<script language='JavaScript' src='http://mathscinet.ru/records/graphics.js'></script>
<form id="mainForm" method=POST enctype=multipart/form-data>
<center><b>ВЕКТОРНЫЙ ЭМУЛЯТОР ETRX357</b>
<table border="1" width="600"><tr height="300">
<td height="300" valign='top' id="wCanvas">
 <div style="position: relative;"> 
 <div id='pCanvas' style='position: relative'></div>
 <div style="position: absolute; left: 10px; top: 10px">
 <img id="led1" src="records/images/green.png"/><br/><sub>LED1</sub>
 </div>
 <div style="position: absolute; left: 50px; top: 10px">
 <img id="led2" src="records/images/green.png"/><br/><sub>LED2</sub>
 </div>
 <div style="position: absolute; left: 90px; top: 10px">
 <img id="pa6" src="records/images/green.png"/><br/><sub>PA6</sub>
 </div>
 <div style="position: absolute; left: 130px; top: 10px">
 <img id="pa7" src="records/images/red.png"/><br/><sub>PA7</sub>
 </div>
</div>
</td></tr><tr><td>

<input type="text" id="inp" value="" style="width: 500px" onKeyPress="return enterKey(event)">
<input type="button" id="send" value="SEND" onclick="document.getElementById('msg').value = getanswer()">
</td></tr><tr><td>
<text-area id="msg" wrap="off" name="msg" rows="3" style="width:500px;"></text-area>
</td></tr><tr></table>

<script language='JavaScript'>

var tick=0; 
XX=600; YY=300; X=0; Y=YY-20; R=40; L=120; H=8;
G='http://mathscinet.ru/images/grass.gif';
P='http://mathscinet.ru/images/parovoz.gif';
S='http://mathscinet.ru/images/stop.gif';
F='http://mathscinet.ru/images/green.gif';
SUN='http://mathscinet.ru/images/sun.gif';
W='http://mathscinet.ru/images/waves.gif';
show();

function animation1(){  
// АНИМАТОР ХОДА ВПЕРЕД
if (tick<300) {
tick++; show(); setTimeout("animation1()",0);  } 
}

function animation2(){  
// АНИМАТОР ХОДА НАЗАД
if (tick>0) {
tick--; show(); setTimeout("animation2()",0);  }  
}

function show(){  
// ПРОГРАММА ОТРИСОВКИ ПАРОВОЗА
OpenCanvas("MyCanvas",XX,YY); 
X=tick;
MyCanvas.clear(); 
MyCanvas.setColor('#002233');
// РЕЛЬСЫ
MyCanvas.fillRect(0,Y,XX-10,10);
// ТЕНДЕР
MyCanvas.setColor('#004455');
MyCanvas.fillRect(X,Y-R/2-5*H,L/2,5*H);
MyCanvas.fillRect(X+L/2,Y-R/2-8*H,L/4,8*H);
MyCanvas.setColor('#AA4455');
MyCanvas.fillRect(X+L/2+L/4,Y-R/2-5*H,L/2+R/4,5*H);
MyCanvas.setColor('#004455');
MyCanvas.fillRect(X,Y-R/2,L+R,H);
// КОЛЕСА
MyCanvas.setColor('#DD7700');
MyCanvas.fillEllipse(X+R/5,Y-R,R,R);
MyCanvas.fillEllipse(X+L-R/5,Y-R,R,R);
// ОТРИСОВКА
MyCanvas.paint(); 
}

function OpenCanvas(name,w,h) {
// СОЗДАТЬ КАНВУ
document.getElementById('wCanvas').style.display='block';
if (arguments.length==0) {  }else{ 
eval("if(typeof("+name+")==='undefined')"+name+"=new jsGraphics('pCanvas')");
// if (arguments.length>1) { document.getElementById('wCanvas').style.width=w;
// if (arguments.length>2) { document.getElementById('wCanvas').style.height=h; }}
}
}

var state=0; /* СОСТОЯНИЕ СЕТИ ETRX (НЕ ОБРАЗОВАНА) */

function enterKey(e) {
// АДАПТАТОР КЛАВИАТУРЫ К ТИПУ БРАУЗЕРА 
  var key;
  if(window.event) key = window.event.keyCode;     //IE
  else key = e.which;     //firefox
  if (key == 13) {
    document.getElementById('send').click()
    return false;
  }
  return true;
}

if (typeof String.prototype.startsWith != 'function') {
  String.prototype.startsWith = function (str){
    return this.slice(0, str.length) == str;
  };
}

if (typeof String.prototype.endsWith != 'function') {
  String.prototype.endsWith = function (str){
    return this.slice(-str.length) == str;
  };
}

function getRandomHex(min, max) {
  return (Math.floor(Math.random() * (max - min + 1)) + min)
    .toString(16).toUpperCase();
}

function isValidNumber(x) {

  return !isNaN(Number("0x"+(x)));
}

function error(code) {
  return "ERROR: " + code;
}

var online = false;
var connected = false;

var LocalMemory = new Array();
LocalMemory["04"]="0021ED00000468C9";

var RemoteMemory = new Array();
RemoteMemory["04"]="000D6F00005C4AB7";
RemoteMemory["0A"]="0";
RemoteMemory["15D"]="0"; // активирует канал АЦП сенсора температуры
RemoteMemory["1511"]="0"; // активирует канал АЦП сенсора света
RemoteMemory["182"]="0"; // вкл сенсор температуры
RemoteMemory["183"]="0"; // вкл сенсор света
RemoteMemory["1F"]="0"; // возвращает показания сенсора температуры
RemoteMemory["22"]="0"; // возвращает показания сенсора света

var WriteProtected = {"04":1, "05":1, "06":1, "07":1};

function onMemoryWrite(address) {
  if (address == "183" || address == "1511") {
    // работает ли датчик света?
    var enabled = RemoteMemory["183"] == "1" && RemoteMemory["1511"] == "1";
    // если включен АЦП и сенсор записываем случайное значение света в память
    RemoteMemory["22"] = enabled ? getRandomHex(10, 1000) : "0";
  }

  if (address == "182" || address == "15D") {
    // работает ли датчик температуры?
    var enabled = RemoteMemory["182"] == "1" && RemoteMemory["15D"] == "1";
    // если включен АЦП и сенсор записываем случайное значение температуры в память
    RemoteMemory["1F"] = enabled ? getRandomHex(10, 40) : "0";
  }

  if (address == "18") {
    var value = RemoteMemory[address];
    switch(value) {
      case "00000000":
        // Включать диоды ATREMS:E627,18=00000000
        document.getElementById('led1').src = "records/images/green.png";
        document.getElementById('led2').src = "records/images/green.png";
        document.getElementById('pa6').src = "records/images/green.png";
        document.getElementById('pa7').src = "records/images/red.png";
        break;
      case "00000040":
        // отключает светодиод PA7 и СТАРТУЕТ АНИМАЦИЮ
        animation1();  
        document.getElementById('pa7').src = "records/images/off.png";
        document.getElementById('pa6').src = "records/images/green.png";
        break;
      case "00000080":
        animation2();
        // отключает светодиод PA6 и СТАРТУЕТ АНИМАЦИЮ
        document.getElementById('pa6').src = "records/images/off.png";
        document.getElementById('pa7').src = "records/images/red.png";
        break;
      case "000000C0":
        // отключает оба светодиода
        document.getElementById('pa6').src = "records/images/off.png";
        document.getElementById('pa7').src = "records/images/off.png";
        break;
      case "00004000":
        // отключает зеленый светодиод LED1
        document.getElementById('led1').src = "records/images/off.png";
        document.getElementById('led2').src = "records/images/green.png";
        break;
      case "00010000":
        // отключает зеленый светодиод LED2
        document.getElementById('led2').src = "records/images/off.png";
        document.getElementById('led1').src = "records/images/green.png";
        break;
    }
  }
}

function getanswer() {
  var request = document.getElementById('inp').value;
  var question = request.toUpperCase();
  show();

  if (question == "+++") {
    connected = false;
    return "CLOSED";
  }

  if (!question.startsWith("AT")) {
    // неправильная команда
    return "02";
  }

  var cmd = request.substr(2);
  var command = question.substr(2);

  if (command == "Z") {
    // Перегрузка, модуль остается в сети
    return "reset";
  }

  if (command == "&F") {
    // Полная перезагрузка, модуль покидает сеть
    online = false;
    connected = false;
    return;
  }

  if (command == "I") {
    // Сообщается номер модуля, номер прошивки и фабричный номер устройства
    return "TELEGESIS ETRX3 R304X " + LocalMemory["04"] + " OK";
  }

  if (command.startsWith("S")) {
    // обращение к локальной памяти
    var eqSignPos = command.indexOf("=");
    var isRead = command.endsWith("?");

    if (
      (eqSignPos == -1 && !isRead) || (eqSignPos > 0 && isRead) ||
      (command.length < 3 || eqSignPos == command.length-1)
    ) {
      return "05"; // неверный параметр
    }

    if (isRead) {
      // чтение регистра
      var address = command.substring(1, command.length-1);
      if (!isValidNumber(address)) {
        return error("05"); // неверный параметр
      }
      if (!(address in LocalMemory)) {
        return "00";
      }
      return LocalMemory[address];
    }
    // запись в регистр
    var address = command.substring(1, eqSignPos);
    var colSign = command.indexOf(':');
    var value = colSign == -1 ? command.substring(eqSignPos+1) : command.substring(eqSignPos+1, colSign);
    if (!isValidNumber(address) || !isValidNumber(value)) {
      return error("05"); // неверный параметр
    }

    if (address in WriteProtected) {
      // защищенная память
      return error("05");
    }

    LocalMemory[address] = value;

    return "OK";
  }

  if (command == "+EN") {
    if (online) {
      // устройство уже в сети
      return error(28);
    }
    else {
      // создает сеть координатора, координатор первым присоединяется к собственной сети
      online = true;
      return "JPAN:25,3D84,7E04AEF1821F433C";
    }
  }

  if (command == "+N") {
    // выдает отмеченные выше параметры: функциональное назначение (COO), канал, питание, пару адресов
    return online ? "+N=COO,25,03,3D84,7E04AEF1821F433C" : "+N=NoPAN OK"; // не в сети
  }

  if (command == "+DASSL") {
    // вынуждает модуль покинуть (свою) сеть
    online = false;
    connected = false;
    return "LeftPAN";
  }

  if (command == "+PANSCAN") {
    // инициирует поиск новых еще не присоединившихся модулей
    return online
      ? "NEWNODE: E627,"+RemoteMemory["04"]+",0000\nSR:00,"+RemoteMemory["04"]+",E627 FFD:"+RemoteMemory["04"]+",E627"
      : error(27); // не найдена сеть
  }

  if (command == "+SN") {
    // сканирования сети с присоединением к сети найденных новых модулей,
    // рапорт о работе координатора возвращает атрибуты подключившихся к сети модулей, в частности, их короткие адреса
    if (!online) {
      // не в сети
      return error(27); // не найдена сеть
    }
    if (connected) {
      // устройство уже в сети и команда (присоединения к сети) не может быть выполнена.
      return error(28);
    }
    connected = true;
    return "SR:00,"+RemoteMemory["04"]+",E627 FFD:"+RemoteMemory["04"]+",E627";
  }

  if (command.startsWith("REMS:")) {
    if (!connected) {
      return error(26); // нет соединения
    }

    var rems = command.substring(5);
    var comaPos = rems.indexOf(",");
    if (comaPos == -1 || comaPos == rems.length-1) {
      return error("05"); // неверный параметр
    }

    var remote = rems.substring(0, comaPos);
    if (remote != "E627" && remote != RemoteMemory["04"]) {
      return error("26"); //не присоединиться (неизвестный узел)
    }

    var remoteCommand = rems.substring(comaPos + 1);

    var eqSignPos = remoteCommand.indexOf("=");
    var isRead = remoteCommand.endsWith("?");

    if (
      (eqSignPos == -1 && !isRead) || (eqSignPos > 0 && isRead) ||
      (remoteCommand.length < 3 || eqSignPos == remoteCommand.length-1)
      ) {
      return error("05"); // неверный параметр
    }

    var address;
    if (isRead) {
      address = remoteCommand.substring(0, remoteCommand.length-1);
      if (!isValidNumber(address)) {
        return error("05"); // неверный параметр
      }
      return "SREAD:E627,"+RemoteMemory["04"]+"," + address + ",00=" +
        (address in RemoteMemory ? RemoteMemory[address] : "00");
    }

    var address = remoteCommand.substring(0, eqSignPos);
    var colSign = remoteCommand.indexOf(':');
    var value = colSign == -1
      ? remoteCommand.substring(eqSignPos+1)
      : remoteCommand.substring(eqSignPos+1, colSign);
    RemoteMemory[address] = value;

    if (!isValidNumber(address) || !isValidNumber(value)) {
      return error("05"); // неверный параметр
    }

    if (address in WriteProtected) {
      // защищенная память
      return error("05");
    }

    onMemoryWrite(address);

    return "SWRITE:E627,"+RemoteMemory["04"]+"," + address + ",00";
  }

  if (
    command.startsWith("+UCAST:") ||
    command.startsWith("+BCAST:")
  ) {
    if (!online) {
      return error(27); // не найдена сеть
    }
    var isBroadCast = command.startsWith("+BCAST");

    var message;
    if (isBroadCast) {
      // BCAST передает через координатор сообщение безадресно
      var comaIndex = command.indexOf(",");
      if (comaIndex == -1) return error("05");
      var nn = command.substring(7, comaIndex);
      if (!isValidNumber(nn) || parseInt(nn) > 30) return error("05");
      message = cmd.substring(comaIndex + 1);
    }
    else {
      // UCAST передает через координатор адресованную модулю текстовую информацию
      var eqIndex = command.indexOf("=");
      if (comaIndex == -1) return error("05");
      var module = command.substring(7, eqIndex);
      if (!isValidNumber(module)) return error("05");
      message = cmd.substring(eqIndex + 1);
    }
    return (isBroadCast ? "BCAST" : "UCAST") + ":7E04AEF1821F433C," + (message.length) + "=" + message;
  }

  if (command.startsWith("+DMODE")) {
    // Не понятно что с этой и другими командами делать
    return "OK";
  }

  // неправильная команда
  return error("02");
}

</script>

 admin

ЭМУЛЯТОР С ПИКСЕЛЬНОЙ ГРАФИКОЙ



Эмулируемая реальная система с модулем управления на базе ETRX

ДЛЯ СТАРТА АНИМАЦИИ НЕОБХОДИМО:
ИНИЦИАЛИЗИРОВАТЬ КООРДИНАТОР
AT+EN
ОБРАЗОВАТЬ СЕТЬ
AT+SN
КОМАНДА ВПЕРЕД
ATREMS:E627,18=00000040
КОМАНДА НАЗАД
ATREMS:E627,18=00000080


<? /* КОД ЭМУЛЯТОРА С АНИМАЦИЕЙ */ ?>
<script language='JavaScript' src='http://mathscinet.ru/records/graphics.js'></script>
<form id="mainForm" method=POST enctype=multipart/form-data>
<center><b>ПИКСЕЛЬНЫЙ ЭМУЛЯТОР ETRX357</b>
<table border="1" width="600"><tr height="300">
<td height="300" valign='top' id="wCanvas">
 <div style="position: relative;"> 
 <div id='pCanvas' style='position: relative'></div>
 <div style="position: absolute; left: 10px; top: 10px">
 <img id="led1" src="records/images/green.png"/><br/><sub>LED1</sub>
 </div>
 <div style="position: absolute; left: 50px; top: 10px">
 <img id="led2" src="records/images/green.png"/><br/><sub>LED2</sub>
 </div>
 <div style="position: absolute; left: 90px; top: 10px">
 <img id="pa6" src="records/images/green.png"/><br/><sub>PA6</sub>
 </div>
 <div style="position: absolute; left: 130px; top: 10px">
 <img id="pa7" src="records/images/red.png"/><br/><sub>PA7</sub>
 </div>
</div>
</td></tr><tr><td>

<input type="text" id="inp" value="" style="width: 500px" onKeyPress="return enterKey(event)">
<input type="button" id="send" value="SEND" onclick="document.getElementById('msg').value = getanswer()">
</td></tr><tr><td>
<text-area id="msg" wrap="off" name="msg" rows="3" style="width:500px;"></text-area>
</td></tr><tr></table>

<script language='JavaScript'>

var tick=0; 
XX=600; YY=300; X=0; Y=YY-20; R=40; L=120; H=8;
G='http://mathscinet.ru/images/grass.gif';
P='http://mathscinet.ru/images/parovoz.gif';
S='http://mathscinet.ru/images/stop.gif';
F='http://mathscinet.ru/images/green.gif';
SUN='http://mathscinet.ru/images/sun.gif';
W='http://mathscinet.ru/images/waves.gif';
show();

function animation1(){  
// АНИМАТОР ХОДА ВПЕРЕД
if (tick<300) {
tick++; show(); setTimeout("animation1()",0);  } 
}

function animation2(){  
// АНИМАТОР ХОДА НАЗАД
if (tick>0) {
tick--; show(); setTimeout("animation2()",0);  }  
}

function show(){  
// ПРОГРАММА ОТРИСОВКИ ПАРОВОЗА
OpenCanvas("MyCanvas",XX,YY); 
X=tick;
MyCanvas.clear(); 
MyCanvas.setColor('#002233');
// СОЛНЦЕ-ТРАВА
MyCanvas.drawImage(SUN,XX-140,20,0,0);
MyCanvas.drawImage(G,0,Y-130,XX-10,50);
MyCanvas.drawImage(W,0,Y-100,XX-10,100);
// ЗНАКИ СВЕТОФОР и СТОП
// MyCanvas.drawImage(F,90,Y-190,0,0);
MyCanvas.drawImage(S,XX-90,Y-210,0,0);
// РЕЛЬСЫ
MyCanvas.fillRect(0,Y,XX-10,10);
// GIF-ПАРОВОЗ
MyCanvas.drawImage(P,X+R,100,0,0);
// ОТРИСОВКА
MyCanvas.paint(); 
}

function OpenCanvas(name,w,h) {
// СОЗДАТЬ КАНВУ
document.getElementById('wCanvas').style.display='block';
if (arguments.length==0) {  }else{ 
eval("if(typeof("+name+")==='undefined')"+name+"=new jsGraphics('pCanvas')");
// if (arguments.length>1) { document.getElementById('wCanvas').style.width=w;
// if (arguments.length>2) { document.getElementById('wCanvas').style.height=h; }}
}
}

var state=0; /* СОСТОЯНИЕ СЕТИ (НЕ ОБРАЗОВАНА) */

function enterKey(e) {
  var key;
  if(window.event) key = window.event.keyCode;     //IE
  else key = e.which;     //firefox
  if (key == 13) {
    document.getElementById('send').click()
    return false;
  }
  return true;
}

if (typeof String.prototype.startsWith != 'function') {
  String.prototype.startsWith = function (str){
    return this.slice(0, str.length) == str;
  };
}

if (typeof String.prototype.endsWith != 'function') {
  String.prototype.endsWith = function (str){
    return this.slice(-str.length) == str;
  };
}

function getRandomHex(min, max) {
  return (Math.floor(Math.random() * (max - min + 1)) + min)
    .toString(16).toUpperCase();
}

function isValidNumber(x) {

  return !isNaN(Number("0x"+(x)));
}

function error(code) {
  return "ERROR: " + code;
}

var online = false;
var connected = false;

var LocalMemory = new Array();
LocalMemory["04"]="0021ED00000468C9";

var RemoteMemory = new Array();
RemoteMemory["04"]="000D6F00005C4AB7";
RemoteMemory["0A"]="0";
RemoteMemory["15D"]="0"; // активирует канал АЦП сенсора температуры
RemoteMemory["1511"]="0"; // активирует канал АЦП сенсора света
RemoteMemory["182"]="0"; // вкл сенсор температуры
RemoteMemory["183"]="0"; // вкл сенсор света
RemoteMemory["1F"]="0"; // возвращает показания сенсора температуры
RemoteMemory["22"]="0"; // возвращает показания сенсора света

var WriteProtected = {"04":1, "05":1, "06":1, "07":1};

function onMemoryWrite(address) {
  if (address == "183" || address == "1511") {
    // работает ли датчик света?
    var enabled = RemoteMemory["183"] == "1" && RemoteMemory["1511"] == "1";
    // если включен АЦП и сенсор записываем случайное значение света в память
    RemoteMemory["22"] = enabled ? getRandomHex(10, 1000) : "0";
  }

  if (address == "182" || address == "15D") {
    // работает ли датчик температуры?
    var enabled = RemoteMemory["182"] == "1" && RemoteMemory["15D"] == "1";
    // если включен АЦП и сенсор записываем случайное значение температуры в память
    RemoteMemory["1F"] = enabled ? getRandomHex(10, 40) : "0";
  }

  if (address == "18") {
    var value = RemoteMemory[address];
    switch(value) {
      case "00000000":
        // Включать диоды ATREMS:E627,18=00000000
        document.getElementById('led1').src = "records/images/green.png";
        document.getElementById('led2').src = "records/images/green.png";
        document.getElementById('pa6').src = "records/images/green.png";
        document.getElementById('pa7').src = "records/images/red.png";
        break;
      case "00000040":
        // отключает светодиод PA7
        animation1();  
        document.getElementById('pa7').src = "records/images/off.png";
        document.getElementById('pa6').src = "records/images/green.png";
        break;
      case "00000080":
        animation2();
        // отключает светодиод PA6
        document.getElementById('pa6').src = "records/images/off.png";
        document.getElementById('pa7').src = "records/images/red.png";
        break;
      case "000000C0":
        // отключает оба светодиода
        document.getElementById('pa6').src = "records/images/off.png";
        document.getElementById('pa7').src = "records/images/off.png";
        break;
      case "00004000":
        // отключает зеленый светодиод LED1
        document.getElementById('led1').src = "records/images/off.png";
        document.getElementById('led2').src = "records/images/green.png";
        break;
      case "00010000":
        // отключает зеленый светодиод LED2
        document.getElementById('led2').src = "records/images/off.png";
        document.getElementById('led1').src = "records/images/green.png";
        break;
    }
  }
}

function getanswer() {
  var request = document.getElementById('inp').value;
  var question = request.toUpperCase();
  show();

  if (question == "+++") {
    connected = false;
    return "CLOSED";
  }

  if (!question.startsWith("AT")) {
    // неправильная команда
    return "02";
  }

  var cmd = request.substr(2);
  var command = question.substr(2);

  if (command == "Z") {
    // Перегрузка, модуль остается в сети
    return "reset";
  }

  if (command == "&F") {
    // Полная перезагрузка, модуль покидает сеть
    online = false;
    connected = false;
    return;
  }

  if (command == "I") {
    // Сообщается номер модуля, номер прошивки и фабричный номер устройства
    return "TELEGESIS ETRX3 R304X " + LocalMemory["04"] + " OK";
  }

  if (command.startsWith("S")) {
    // обращение к локальной памяти
    var eqSignPos = command.indexOf("=");
    var isRead = command.endsWith("?");

    if (
      (eqSignPos == -1 && !isRead) || (eqSignPos > 0 && isRead) ||
      (command.length < 3 || eqSignPos == command.length-1)
    ) {
      return "05"; // неверный параметр
    }

    if (isRead) {
      // чтение регистра
      var address = command.substring(1, command.length-1);
      if (!isValidNumber(address)) {
        return error("05"); // неверный параметр
      }
      if (!(address in LocalMemory)) {
        return "00";
      }
      return LocalMemory[address];
    }
    // запись в регистр
    var address = command.substring(1, eqSignPos);
    var colSign = command.indexOf(':');
    var value = colSign == -1 ? command.substring(eqSignPos+1) : command.substring(eqSignPos+1, colSign);
    if (!isValidNumber(address) || !isValidNumber(value)) {
      return error("05"); // неверный параметр
    }

    if (address in WriteProtected) {
      // защищенная память
      return error("05");
    }

    LocalMemory[address] = value;

    return "OK";
  }

  if (command == "+EN") {
    if (online) {
      // устройство уже в сети
      return error(28);
    }
    else {
      // создает сеть координатора, координатор первым присоединяется к собственной сети
      online = true;
      return "JPAN:25,3D84,7E04AEF1821F433C";
    }
  }

  if (command == "+N") {
    // выдает отмеченные выше параметры: функциональное назначение (COO), канал, питание, пару адресов
    return online ? "+N=COO,25,03,3D84,7E04AEF1821F433C" : "+N=NoPAN OK"; // не в сети
  }

  if (command == "+DASSL") {
    // вынуждает модуль покинуть (свою) сеть
    online = false;
    connected = false;
    return "LeftPAN";
  }

  if (command == "+PANSCAN") {
    // инициирует поиск новых еще не присоединившихся модулей
    return online
      ? "NEWNODE: E627,"+RemoteMemory["04"]+",0000\nSR:00,"+RemoteMemory["04"]+",E627 FFD:"+RemoteMemory["04"]+",E627"
      : error(27); // не найдена сеть
  }

  if (command == "+SN") {
    // сканирования сети с присоединением к сети найденных новых модулей,
    // рапорт о работе координатора возвращает атрибуты подключившихся к сети модулей, в частности, их короткие адреса
    if (!online) {
      // не в сети
      return error(27); // не найдена сеть
    }
    if (connected) {
      // устройство уже в сети и команда (присоединения к сети) не может быть выполнена.
      return error(28);
    }
    connected = true;
    return "SR:00,"+RemoteMemory["04"]+",E627 FFD:"+RemoteMemory["04"]+",E627";
  }

  if (command.startsWith("REMS:")) {
    if (!connected) {
      return error(26); // нет соединения
    }

    var rems = command.substring(5);
    var comaPos = rems.indexOf(",");
    if (comaPos == -1 || comaPos == rems.length-1) {
      return error("05"); // неверный параметр
    }

    var remote = rems.substring(0, comaPos);
    if (remote != "E627" && remote != RemoteMemory["04"]) {
      return error("26"); //не присоединиться (неизвестный узел)
    }

    var remoteCommand = rems.substring(comaPos + 1);

    var eqSignPos = remoteCommand.indexOf("=");
    var isRead = remoteCommand.endsWith("?");

    if (
      (eqSignPos == -1 && !isRead) || (eqSignPos > 0 && isRead) ||
      (remoteCommand.length < 3 || eqSignPos == remoteCommand.length-1)
      ) {
      return error("05"); // неверный параметр
    }

    var address;
    if (isRead) {
      address = remoteCommand.substring(0, remoteCommand.length-1);
      if (!isValidNumber(address)) {
        return error("05"); // неверный параметр
      }
      return "SREAD:E627,"+RemoteMemory["04"]+"," + address + ",00=" +
        (address in RemoteMemory ? RemoteMemory[address] : "00");
    }

    var address = remoteCommand.substring(0, eqSignPos);
    var colSign = remoteCommand.indexOf(':');
    var value = colSign == -1
      ? remoteCommand.substring(eqSignPos+1)
      : remoteCommand.substring(eqSignPos+1, colSign);
    RemoteMemory[address] = value;

    if (!isValidNumber(address) || !isValidNumber(value)) {
      return error("05"); // неверный параметр
    }

    if (address in WriteProtected) {
      // защищенная память
      return error("05");
    }

    onMemoryWrite(address);

    return "SWRITE:E627,"+RemoteMemory["04"]+"," + address + ",00";
  }

  if (
    command.startsWith("+UCAST:") ||
    command.startsWith("+BCAST:")
  ) {
    if (!online) {
      return error(27); // не найдена сеть
    }
    var isBroadCast = command.startsWith("+BCAST");

    var message;
    if (isBroadCast) {
      // BCAST передает через координатор сообщение безадресно
      var comaIndex = command.indexOf(",");
      if (comaIndex == -1) return error("05");
      var nn = command.substring(7, comaIndex);
      if (!isValidNumber(nn) || parseInt(nn) > 30) return error("05");
      message = cmd.substring(comaIndex + 1);
    }
    else {
      // UCAST передает через координатор адресованную модулю текстовую информацию
      var eqIndex = command.indexOf("=");
      if (comaIndex == -1) return error("05");
      var module = command.substring(7, eqIndex);
      if (!isValidNumber(module)) return error("05");
      message = cmd.substring(eqIndex + 1);
    }
    return (isBroadCast ? "BCAST" : "UCAST") + ":7E04AEF1821F433C," + (message.length) + "=" + message;
  }

  if (command.startsWith("+DMODE")) {
    // Не понятно что с этой и другими командами делать
    return "OK";
  }

  // неправильная команда
  return error("02");
}

</script>

 admin

ПРИМЕРЫ ГРАФИЧЕСКИХ МОДЕЛЕЙ

Для GIF-анимации можно присмотреть на серверах травку, кусты и т.п.

ГРАФИКА ДЛЯ ИНТЕРНЕТ

SVG (от англ. Scalable Vector Graphics — масштабируемая векторная графика) — язык разметки масштабируемой векторной графики, созданный Консорциумом Всемирной паутины (W3C) и входящий в подмножество расширяемого языка разметки XML, предназначен для описания двумерной векторной и смешанной векторно/растровой графики в формате XML.

Поддерживает как неподвижную, так анимированную и интерактивную графику — или, в иных терминах, декларативную и скриптовую. Не поддерживает описание трёхмерных объектов (не путать с имитацией трёхмерности путём светотени). Это открытый стандарт, является рекомендацией консорциума W3C, — организации, разработавшей такие стандарты, как HTML и XHTML.

Разрабатывается с 1999 года, в 2001 году вышла 1.1 версия, которая остается актуальной до сегодняшнего дня, в активной разработке версия 1.2. В основу SVG легли языки разметки VML и PGML.

Недостаток SVG-графики для проекта состоит в том, что она введена поздно и работает начиная с браузеров Windows 7. Таким образом, страницы с нею будут не видны во всех предыдущих браузерах. Это перспектива и стандарт будущего.

ГРАФИЧЕСКИЕ АДАПТАТОРЫ

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



// ЗАГРУЗКА ГРАФИЧЕСКОГО АДАПТАТОРА
<script src="http://mathscinet.ru/records/raphael.js" type="text/javascript" charset="utf-8"></script>

<script>
// ОПИСАНИЕ ДЕЙСТВИЙ ПРИ ОТКРЫТИИ ОКНА БРАУЕРА
window.onload = function () {

// ОТКРЫТЬ КАНВУ ИЗОБРАЖЕНИЯ 320x200
var paper = Raphael("holder", 320, 200);

// НАРИСОВАТЬ КРУГ В ТОЧКЕ x = 50, y = 40 РАДИУСОМ 30
var circle = paper.circle(50, 40, 30);
// УСТАНОВИТЬ АТРИБУТЫ КРУГА - ЗАПОЛНЕНИЕ И КРАСНЫЙ ЦВЕТ (#f00)
circle.attr("fill", "#f00");
// УСТАНОВИТЬ АТРИБУТЫ КРАЯ КРУГА
circle.attr("stroke", "#fff");

};
</script>

Пример другого адаптатора (движка) для графики описан ниже, его библиотека заметно меньше, чем у Raphael, размер не 230 кб, а 30 кб, подгружается он быстрее и взят, по этой причине, за основу в Java-Matlab. Фактически, это графическая часть библиотеки матричной математики и графики для математических расчетов, используемая в интернет-сети, где и инсталлирован текстовой эмулятор ETRX, который дорабатывается с целью эмуляции управляемых объектов. Довольно логично, что именно он выбирается при доработке эмулятора.

Канва создается эмулятором OpenCanvas('S',w,h) с заданным именем слоя S и размерами wxh, при циклическом выполненнии программы кана создается только один раз (при втором обращении к оператору и далее она не создается, а только используется).

Слоев на канве можно создать несколько, содержимое слоя очищается по S.clear().

Перед отрисовкой фигуры слоя S задается RGB-цвет ее по S.setColor('#FF0000'), для строки – еще и шрифт, размер и стиль оператором S.setFont(name,size,style), строка позиционирует на экране явным указанием ее координат S.drawString('строка',x,y).

Самое простое – выводить GIF-рисунок с заданным в сети адресом его размещения при помощи оператора S.drawImage('адрес',x,y,w,h), ширина и высота w=0 и h=0, если размер неизвестен.

Отрисовка всех указанных такими операторами фигур завершается по S.paint().

Для организации анимации определенное значение имеет оператор рестарта сценария restart(ожидание) в сочетании с показателем счетчика циклов tick, позволяющий задавать начальные значения переменных. В примере подвижный прямоугольник перемещается на фоне рисунка.

Есть стандартные графические операторы вывода (заданной векторами координат) ломаной линии S.drawPolyline(X,Y,style), прямоугольников S.drawRect(x,y,w,h), S.fillRect(x,y,w,h), вписанных в них эллипсов S.drawEllipse(x,y,w,h), S.fillEllipse(x,y,w,h) и полигонов S.drawPolygon(X,Y), S.fillPolygon(X,Y).

Несколько слов про слои изображения (тут).

 Ganin

ПРИМЕР В ВЕКТОРНОЙ ГРАФИКЕ

Ниже размещен пример сетевой анимации, решенный в векторной графике с комментариями. Описание средств создания интерфейса (кнопок, полей), используемого на форме ниже, приведено тут: (CGI-интерфейс). Рисунок примитивизирован специально, чтобы не усложнять вида программы контрольного примера.


<? /* ПОДГРУЗКА АДАПТАТОРА */ ?>
<script language='JavaScript' src='http://mathscinet.ru/records/graphics.js'></script>
<form id="mainForm" method=POST enctype=multipart/form-data>
<center><b>ЗАГОЛОВОК: ВЕКТОРНАЯ ГРАФИКА</b>
<table border="1" width="600">
<tr><td valign='top' id="wCanvas">
<div id='pCanvas' style='position: relative'></div>
<tr><td>
<input type="text" id="inp" value="" style="width: 500"> 
<input type="button" value="RUN" onclick="getanswer()">
</td></tr><tr><td>
<input type="text" id="out" value="" style="width: 500">
</td></tr><tr></table>

<script language='JavaScript'>
// ЭМУЛЯЦИЯ ПОДВИЖНОЙ ФИГУРЫ
var tick=0; // ТИК ТАЙМЕРА ФИЛЬМА
// РАЗМЕРЫ ЭКРАНА И ЧАСТЕЙ ФИГУРЫ ДЛИНОЙ L
XX=600; YY=300; X=0; Y=YY-20; R=40; L=120; H=8;

function getanswer(){  
// ПОДПРОГРАММА МУЛЬТИПЛИКАЦИИ
if (tick==0) { 
// СОЗДАНИЕ КАНВЫ
OpenCanvas("MyCanvas",XX,YY);
}else{
// КООРДИНАТА ПОДВИЖНОЙ ФИГУРЫ
X=tick;
// ОЧИСТКА КАНВЫ
MyCanvas.clear(); 
// ЦВЕТ РЕЛЬС
MyCanvas.setColor('#002233');
// ОТРИСОВАТЬ РЕЛЬСЫ
MyCanvas.fillRect(0,Y,XX-10,10);
// ЦВЕТ И РИСУНОК ТЕНДЕРА ПАРОВОЗА
MyCanvas.setColor('#004455');
MyCanvas.fillRect(X,Y-R/2-5*H,L/2,5*H);
MyCanvas.fillRect(X+L/2,Y-R/2-8*H,L/4,8*H);
// ЦВЕТ И РИСУНОК БАКА ПАРОВОЗА
MyCanvas.setColor('#AA4455');
MyCanvas.fillRect(X+L/2+L/4,Y-R/2-5*H,L/2+R/4,5*H);
// ЦВЕТ И РИСУНОК КАБИНЫ ПАРОВОЗА
MyCanvas.setColor('#004455');
MyCanvas.fillRect(X,Y-R/2,L+R,H);
// ЦВЕТ И ОТРИСОКА КОЛЕС
MyCanvas.setColor('#DD7700');
MyCanvas.fillEllipse(X+R/5,Y-R,R,R);
MyCanvas.fillEllipse(X+L-R/5,Y-R,R,R);
// ИЗОБРАЗИТЬ
MyCanvas.paint();
}
// РЕСТАРТ 300 РАЗ ЧЕРЕЗ 10 МИКРОСЕКУНД
if (tick<300) { tick++; setTimeout("getanswer()",10);  
// ОСТАНОВ
}else{tick=0;}  
}

function OpenCanvas(name,w,h) {
// СОЗДАТЬ КАНВУ
// КРАТКОЕ ПЕРЕЧИСЛЕНИЕ ОПЕРАТОРОВ
// MyCanvas.clear(); 
// MyCanvas.drawImage(name,x,y,w,h);
// name=name+"?"+Math.random(); 
// MyCanvas.setColor('#FF0000');
// MyCanvas.drawString(string,x,y);
// MyCanvas.fillRect(x,y,w,h);
// MyCanvas.fillPolygon(x,y);
// MyCanvas.paint() 
// РАСШИРИТЬ БЛОК ТАБЛИЦЫ С ИМЕНЕМ wCanvas
document.getElementById('wCanvas').style.display='block';
if (arguments.length==0) {  }else{ 
// СОЗДАНИЕ КАНВЫ СРЕДСТВАМИ БИБЛИОТЕКИ АДАПТАТОРА 
eval("if(typeof("+name+")==='undefined')"+name+"=new jsGraphics('pCanvas')");
if (arguments.length>1) { document.getElementById('wCanvas').style.width=w;
if (arguments.length>2) { document.getElementById('wCanvas').style.height=h; }}}
}
</script>

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

 admin

ПРИМЕР В ПИКСЕЛЬНОЙ ГРАФИКЕ

Ниже размещен пример сетевой анимации, решенный в пиксельной графике с комментариями. Кнопочный интерфейс тот же самый


<? /* ЗАГРУЗКА АДАПТАТОРА */ ?>
<script language='JavaScript' src='http://mathscinet.ru/records/graphics.js'></script>
<form id="mainForm" method=POST enctype=multipart/form-data>
<center><b>ЗАГОЛОВОК: ПИКСЕЛЬНАЯ ГРАФИКА</b>
<table border="1" width="600">
<tr><td valign='top' id="wCanvas"><div id='pCanvas' style='position: relative'></div>
<tr><td>
<input type="text" id="inp" value="" style="width: 500"> 
<input type="button" value="RUN" onclick="getanswer()">
</td></tr><tr><td>
<input type="text" id="out" value="" style="width: 500">
</td></tr><tr></table>

<script language='JavaScript'>
// ЭМУЛЯЦИЯ ПОДВИЖНОЙ ФИГУРЫ
var tick=0; // ТИК ТАЙМЕРА ФИЛЬМА
// РАЗМЕРЫ ЭКРАНА И ЧАСТЕЙ ФИГУРЫ ДЛИНОЙ L
XX=600; YY=300; X=0; Y=YY-20; R=40; L=120; H=8;
// АДРЕСА GIF-РИСУНКОВ
G='http://mathscinet.ru/images/grass.gif';
P='http://mathscinet.ru/images/parovoz.gif';
S='http://mathscinet.ru/images/stop.gif';
F='http://mathscinet.ru/images/green.gif';
SUN='http://mathscinet.ru/images/sun.gif';
W='http://mathscinet.ru/images/waves.gif';

function getanswer(){  
// ПОДПРОГРАММА МУЛЬТИПЛИКАЦИИ
if (tick==0) { 
// СОЗДАНИЕ КАНВЫ
OpenCanvas("MyCanvas",XX,YY);
}else{
// КООРДИНАТА ПОДВИЖНОЙ ФИГУРЫ
X=tick;
// ОЧИСТКА КАНВЫ
MyCanvas.clear(); 
// СОЛНЦЕ-ТРАВА в GIF-АНИМАЦИИ
MyCanvas.drawImage(SUN,XX-140,20,0,0);
MyCanvas.drawImage(G,0,Y-130,XX-10,50);
MyCanvas.drawImage(W,0,Y-100,XX-10,100);
// ЗНАКИ СВЕТОФОР и СТОП
MyCanvas.drawImage(F,90,Y-190,0,0);
MyCanvas.drawImage(S,XX-90,Y-210,0,0);
// УСТАНОВКА ЦВЕТА РЕЛЬС
MyCanvas.setColor('#002233');
// РЕЛЬСЫ
MyCanvas.fillRect(0,Y,XX-10,10);
// GIF-ПАРОВОЗ
MyCanvas.drawImage(P,X+R,100,0,0); 
// ИЗОБРАЗИТЬ
MyCanvas.paint();
}
// РЕСТАРТ 300 РАЗ ЧЕРЕЗ 10 МИКРОСЕКУНД
if (tick<300) { tick++; setTimeout("getanswer()",10);  
// ОСТАНОВ
}else{tick=0;}  
}

function OpenCanvas(name,w,h) {
// СОЗДАТЬ КАНВУ
// КРАТКОЕ ПЕРЕЧИСЛЕНИЕ ОПЕРАТОРОВ
// MyCanvas.clear(); 
// MyCanvas.drawImage(name,x,y,w,h);
// name=name+"?"+Math.random(); 
// MyCanvas.setColor('#FF0000');
// MyCanvas.drawString(string,x,y);
// MyCanvas.fillRect(x,y,w,h);
// MyCanvas.fillPolygon(x,y);
// MyCanvas.paint() 
// РАСШИРИТЬ БЛОК ТАБЛИЦЫ С ИМЕНЕМ wCanvas
document.getElementById('wCanvas').style.display='block';
if (arguments.length==0) {  }else{ 
// СОЗДАНИЕ КАНВЫ СРЕДСТВАМИ БИБЛИОТЕКИ АДАПТАТОРА 
eval("if(typeof("+name+")==='undefined')"+name+"=new jsGraphics('pCanvas')");
if (arguments.length>1) { document.getElementById('wCanvas').style.width=w;
if (arguments.length>2) { document.getElementById('wCanvas').style.height=h; }}}
}
</script>

Преимущество пиксельной графики состоит в наличии большого числа готовых примеров изображений и примитивов. Недостатком можно считать ограничение скорости загрузки GIF-изображений быстродействием канала Интернет. Невозможно работать с медленным модемом.



Rambler's Top100