fixed msp device in accordance with new device framework

This commit is contained in:
darksnake 2016-02-04 16:55:50 +03:00
parent 2503e22b38
commit cbcace34d8
3 changed files with 645 additions and 180 deletions

View File

@ -0,0 +1,489 @@
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<meta name=Generator content="Microsoft Word 15 (filtered)">
<style>
</style>
</head>
<body lang=RU style='line-break:strict'>
<div class=WordSection1>
<table class=MsoNormalTable border=1 cellspacing=0 cellpadding=0
style='margin-left:3.55pt;border-collapse:collapse;border:none'>
<tr style='height:8.5pt'>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1>&nbsp;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border:solid windowtext 1.0pt;
border-left:none;padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1><span lang=EN-US>MKSRGA  Multi</span></p>
<p class=a1><span lang=EN-US>Protocol_Revision 1.1</span></p>
<p class=a1><span lang=EN-US>Min_Compatibility 1.1</span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border:solid windowtext 1.0pt;
border-left:none;padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1>Асинхронное сообщение о подключении к прибору по tcp-ip</p>
</td>
</tr>
<tr style='height:8.5pt'>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1><span style='background:yellow'>&nbsp;</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1><span lang=EN-US style='background:yellow'>«command»     ERROR </span></p>
<p class=a1><span lang=EN-US style='background:yellow'>Number           
200   </span></p>
<p class=a1><span lang=EN-US style='background:yellow'>Description      «err
description»* </span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:8.5pt'>
<p class=a1><span style='background:yellow'>В случае ошибки возвращается это
сообщение</span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Sensors</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span lang=EN-US>Sensors OK   </span></p>
<p class=a1><span lang=EN-US>State     SerialNumber            Name</span></p>
<p class=a1><span lang=EN-US>Ready   LM70-00197021  “Chamber A”</span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Выдает все сенсоры, которые могут быть использованы</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Select &quot;SerialNumber&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span lang=EN-US>Select OK</span></p>
<p class=a1><span lang=EN-US>SerialNumber  LM70-00197021</span></p>
<p class=a1><span lang=EN-US>State         Ready  </span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Выбираем сенсор, с которым будем работать</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Control &quot;AppName&quot; &quot;Version&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Control OK</p>
<p class=a1>SerialNumber  LM70-00197021</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Получаем контроль над сенсором</p>
</td>
</tr>
<tr>
<td width=181 rowspan=2 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>FilamentControl          </p>
<p class=a1>&quot;On/Off&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>FilamentControl OK </p>
<p class=a1>State On</p>
<p class=a1>&nbsp;</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Включение нити накала</p>
</td>
</tr>
<tr>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span lang=EN-US>FilamentStatus 1    ON/OFF/WARM-UP/COOL- DOWN</span></p>
<p class=a1><span lang=EN-US>Trip                        None </span></p>
<p class=a1><span lang=EN-US>Drive                       Off</span></p>
<p class=a1><span lang=EN-US>EmissionTripState   OK</span></p>
<p class=a1>ExternalTripState    OK </p>
<p class=a1>RVCTripState          OK</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Асинхронное сообщение о любом изменении состояния нити накала</p>
<p class=a1>Последовательность<span lang=EN-US> : WARM-UP -&gt; OK -&gt; ON </span>или<span
lang=EN-US> COOL-DOWN -&gt; OK -&gt; OFF</span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>AddPeakJump &quot;MeasurementName&quot; &quot;FilterMode&quot;
&quot;0..8&quot; &quot;0&quot; &quot;0&quot; &quot;0&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span lang=EN-US>AddPeakJump OK</span></p>
<p class=a1><span lang=EN-US>Name                   PeakJump1</span></p>
<p class=a1><span lang=EN-US>FilterMode          
PeakCenter/PeakMax/PeakAverage</span></p>
<p class=a1>Accuracy                 5</p>
<p class=a1>EGainIndex             0 </p>
<p class=a1>SourceIndex            0</p>
<p class=a1>DetectorIndex          0 </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Создаем режим измерения PeakJump</p>
<p class=a1>0..8 — точность измерений: 0 — меньшая точность, но большая
скорость, 8 — наоборот </p>
<p class=a1>Все остальное полагать 0</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>MeasurementAddMass &quot;Mass&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>MeasurementAddMass  OK</p>
<p class=a1>Mass  10</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Добавляем массы в PeakJump, которые хотим измерить.</p>
<p class=a1>Чтобы добавить новую массу, нужно повторно вызвать эту команду.</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementChangeMass </span></p>
<p class=a1><span style='background:yellow'>&quot;</span><span lang=EN-US
style='background:yellow'>MassIndex&quot; &quot;NewMass&quot;</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementChangeMass OK
MassIndex                          0   </span></p>
<p class=a1><span style='background:yellow'>NewMass                           6 
</span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>Заменяет массу с индексом &quot;
MassIndex&quot; на новое значение</span></p>
<p class=a1><span style='background:yellow'>(индексация с нуля)</span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementSelect &quot;Analog1</span><span
lang=EN-US style='background:yellow'>&quot;</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementSelect      OK</span></p>
<p class=a1><span style='background:yellow'>Measurement               
Analog1 </span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>Определяет </span><span
lang=EN-US style='background:yellow'>Measurement</span><span lang=EN-US
style='background:yellow'> </span><span style='background:yellow'>по его
имени, который будет использоваться в дальнейшем для </span><span lang=EN-US
style='background:yellow'>MeasurementXXXX</span><span lang=EN-US
style='background:yellow'> </span><span style='background:yellow'>команд </span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementRemoveAll</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementRemoveAll OK </span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>Удаляет все </span><span
lang=EN-US style='background:yellow'>Measurements</span><span lang=EN-US
style='background:yellow'> </span><span style='background:yellow'>из списка
сканера</span></p>
<p class=a1><span style='background:yellow'>&nbsp;</span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementRemove
&quot;Barchart1&quot;</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>MeasurementRemove   OK  
Measurement                Barchart1 </span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>Удаляет </span><span lang=EN-US
style='background:yellow'>Measurement</span><span lang=EN-US
style='background:yellow'> </span><span style='background:yellow'>с данным
именем из списка сканера</span></p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanAdd &quot;MeasurementName&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanAdd OK</p>
<p class=a1>Measurement PeakJump1</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Добавляем созданное измерение сканеру.</p>
<p class=a1>Сканер НЕ должен быть запущен.</p>
</td>
</tr>
<tr>
<td width=181 rowspan=5 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanStart &quot;NumScans&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanStart OK </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Запускаем сканер.</p>
<p class=a1>Далее - асинхронные сообщения после каждого из <span lang=EN-US>NumScans</span>
сканирования. </p>
</td>
</tr>
<tr>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>StartingScan  1 16858 0</p>
<p class=a1>&nbsp;</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Сообщение о том, что закончилось некоторое измерение, указано
время с момента первого измерения и оставшееся количество измерений до
перезапуска</p>
</td>
</tr>
<tr>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>StartingMeasurement PeakJump1</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Сообщение о том, какой Measurment сканера запущен (сканер может
иметь несколько режимов измерений)</p>
</td>
</tr>
<tr>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ZeroReading 5.5 1.01e-8</p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Нулевое значени давления ( 5.5 - это MassPosition)</p>
<p class=a1>Изменяется командой:   MeasurementZeroMass &quot;ZeroMass&quot;</p>
</td>
</tr>
<tr>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>MassReading 1 2.9383e-5 </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Парциальное давление газа заданной массы в формате масса,
давление (выводится весь список масс)</p>
<p class=a1>Далее сканер остается запущенным в режиме ожидания</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanResume &quot;NumScans&quot;</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>ScanResume  OK </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1>Продолжает работу сканера для повторного считывания данных с
последующей цепочкой аналогичных сообщений</p>
</td>
</tr>
<tr>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>ScanRestart &quot;</span><span
lang=EN-US style='background:yellow'>NumScans&quot;</span></p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>ScanRestart  OK</span></p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt'>
<p class=a1><span style='background:yellow'>Перезапускает сканер с самого
начала для &quot;</span><span lang=EN-US style='background:yellow'>NumScans</span><span
style='background:yellow'>&quot; измерений </span></p>
<p class=a1><span style='background:yellow'>(полезно в случае сбоев
сканирования, чтобы заново не переопределять параметры сенсора)</span></p>
</td>
</tr>
<tr style='height:10.65pt'>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt;height:10.65pt'>
<p class=a1>ScanStop</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:10.65pt'>
<p class=a1>ScanStop OK </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:10.65pt'>
<p class=a1>Выключает сканер и сбрасывает с него все имеющиеся Measurements</p>
<p class=a1>Для следующих измерений нужно снова ScanAdd
&quot;MeasurementName&quot;</p>
</td>
</tr>
<tr style='height:3.55pt'>
<td width=181 valign=top style='width:136.0pt;border:solid windowtext 1.0pt;
border-top:none;padding:2.75pt 2.75pt 2.75pt 2.75pt;height:3.55pt'>
<p class=a1>Release</p>
</td>
<td width=246 valign=top style='width:184.5pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:3.55pt'>
<p class=a1>Release OK </p>
</td>
<td width=215 valign=top style='width:161.0pt;border-top:none;border-left:
none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
padding:2.75pt 2.75pt 2.75pt 2.75pt;height:3.55pt'>
<p class=a1>Теряем контроль над сенсором</p>
</td>
</tr>
</table>
<p class=MsoNormal><span style='background:yellow'>* номера и описания ошибок:</span></p>
<p class=MsoNormal><span lang=EN-US style='background:yellow'>200 </span><span
style='background:yellow'>некорректная команда</span></p>
<p class=MsoNormal><span style='background:yellow'>201 — неверное количество
параметров в команде</span></p>
<p class=MsoNormal><span lang=EN-US style='background:yellow'>202 </span><span
style='background:yellow'>ошибочно</span><span style='background:yellow'> </span><span
style='background:yellow'>переданный</span><span style='background:yellow'> </span><span
style='background:yellow'>параметр</span><span lang=EN-US style='background:
yellow'> (Parameter 1 'State' could not be interpreted as on/off)</span></p>
<p class=MsoNormal><span lang=EN-US style='background:yellow'>203 </span><span
style='background:yellow'>ошибка</span><span style='background:yellow'> </span><span
style='background:yellow'>действия</span><span lang=EN-US style='background:
yellow'>, </span><span style='background:yellow'>подразумевающего</span><span
style='background:yellow'> </span><span style='background:yellow'>корректное</span><span
style='background:yellow'> </span><span style='background:yellow'>выполнение</span><span
style='background:yellow'> </span><span style='background:yellow'>какого</span><span
style='background:yellow'> </span><span style='background:yellow'>либо</span><span
style='background:yellow'> </span><span style='background:yellow'>другого</span><span
style='background:yellow'> </span><span style='background:yellow'>действия</span><span
lang=EN-US style='background:yellow'>  (No sensor selected/Must be in control
of sensor/Not scanning)</span></p>
<p class=MsoNormal><span lang=EN-US style='background:yellow'>204 </span><span
style='background:yellow'>ошибка</span><span style='background:yellow'> </span><span
style='background:yellow'>в</span><span style='background:yellow'> </span><span
style='background:yellow'>параметрах</span><span lang=EN-US style='background:
yellow'>, </span><span style='background:yellow'>связанных</span><span
style='background:yellow'> </span><span style='background:yellow'>с</span><span
style='background:yellow'> <span lang=EN-US>Measurement (Measurement with this
name already exists/Bad SourceIndex/Invalid mass value)</span></span></p>
<p class=MsoNormal><span style='background:yellow'>300 ошибка выбора сенсора
(неверный серийный номер сенсора)</span></p>
<p class=MsoNormal>&nbsp;</p>
</div>
</body>
</html>

View File

@ -17,6 +17,7 @@ package inr.numass.control.msp;
import hep.dataforge.context.Context;
import hep.dataforge.context.GlobalContext;
import hep.dataforge.control.connections.StorageConnection;
import hep.dataforge.control.devices.SingleMeasurementDevice;
import hep.dataforge.control.measurements.AbstractMeasurement;
import hep.dataforge.control.measurements.Measurement;
@ -34,7 +35,6 @@ import hep.dataforge.meta.Meta;
import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage;
import hep.dataforge.storage.commons.LoaderFactory;
import hep.dataforge.storage.loaders.ChainPointLoader;
import hep.dataforge.values.Value;
import java.time.Instant;
import java.util.ArrayList;
@ -43,36 +43,24 @@ import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.function.Consumer;
/**
*
* @author Alexander Nozik
*/
public class MspDevice extends SingleMeasurementDevice {
public class MspDevice extends SingleMeasurementDevice implements PortHandler.PortController {
// private static final String PEAK_SET_PATH = "peakJump.peak";
private static final int TIMEOUT = 200;
//storage
// /**
// * Separate storage configuration for backup storage.
// */
// private Meta backupStorage;
private PointLoader peakJumpLoader;
//port handler
private TcpPortHandler handler;
//listener
private MspListener mspListener;
private String sensorName = null;
private boolean isSelected = false;
private boolean isControlled = false;
private boolean isFilamentOn = false;
// private boolean isScanning = false;
private Consumer<MspResponse> responseDelegate;
private Consumer<Throwable> errorDelegate;
public MspDevice(String name, Meta annotation) {
super(name, GlobalContext.instance(), annotation);
@ -90,6 +78,28 @@ public class MspDevice extends SingleMeasurementDevice {
getLogger().info("Connection to MKS mass-spectrometer on {}:{}...", ip, port);
handler = new TcpPortHandler(ip, port, "msp");
handler.setDelimeter("\r\r");
handler.holdBy(this);
setConnected(true);
}
@Override
public void shutdown() throws ControlException {
super.shutdown();
super.stopMeasurement(true);
setFileamentOn(false);
setConnected(false);
handler.unholdBy(this);
handler.close();
}
@Override
protected Meta getMetaForMeasurement(String name) {
switch (name) {
case "peakJump":
return meta().getNode("peakJump");
default:
return super.getMetaForMeasurement(name);
}
}
@Override
@ -104,7 +114,14 @@ public class MspDevice extends SingleMeasurementDevice {
@Override
protected Object calculateState(String stateName) throws ControlException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
switch (stateName) {
case "filamentOn":
return false;//Always return false on first request
case "filamentStatus":
return "UNKNOWN";
default:
throw new ControlException("State not defined");
}
}
@Override
@ -114,7 +131,14 @@ public class MspDevice extends SingleMeasurementDevice {
@Override
protected boolean applyState(String stateName, Value stateValue) throws ControlException {
switch (stateName) {
case "connected":
return setConnected(stateValue.booleanValue());
case "filamentOn":
return setFileamentOn(stateValue.booleanValue());
default:
return super.applyState(stateName, stateValue);
}
}
/**
@ -123,96 +147,43 @@ public class MspDevice extends SingleMeasurementDevice {
* @param measurement
* @throws hep.dataforge.exceptions.PortException
*/
public void setConnected(boolean connected) throws ControlException {
if (getState("connection").booleanValue() != connected) {
// if (handler.isLocked()) {
// LoggerFactory.getLogger(getClass()).error("Trying to init MSP controller on locked port. Breaking the lock.");
// handler.breakHold();
// }
// handler.holdBy(this);
public boolean setConnected(boolean connected) throws ControlException {
String sensorName;
if (isConnected() != connected) {
if (connected) {
MspResponse response = sendAndWait("Sensors");
if (response.isOK()) {
this.sensorName = response.get(2, 1);
sensorName = response.get(2, 1);
} else {
evaluateError(response.errorDescription(), null);
return;
error(response.errorDescription(), null);
return false;
}
//PENDING определеить в конфиге номер прибора
response = sendAndWait("Select", sensorName);
if (response.isOK()) {
this.isSelected = true;
updateState("selected", true);
} else {
evaluateError(response.errorDescription(), null);
return;
error(response.errorDescription(), null);
return false;
}
response = sendAndWait("Control", "inr.numass.msp", "1.0");
if (response.isOK()) {
this.isControlled = true;
updateState("controlled", true);
} else {
evaluateError(response.errorDescription(), null);
error(response.errorDescription(), null);
return false;
}
updateState("", TIMEOUT);
updateState("connected", true);
return true;
} else {
return !sendAndWait("Release").isOK();
}
} else {
return false;
}
// createPeakJumpMeasurement(buildMeasurementLaminate(measurement).getNode("peakJump"));
// this.peakJumpLoader = getPeakJumpLoader(measurement);
}
// public void setStorageConfig(Meta storageConfig, List<String> peaks) throws StorageException {
// Storage storage = getContext().provide("storage", StoragePlugin.class).buildStorage(storageConfig);
// String suffix = Integer.toString((int) Instant.now().toEpochMilli());
//
// this.peakJumpLoader = LoaderFactory.buildPointLoder(storage, "msp" + suffix, "", "timestamp", DataFormat.forNames(10, peaks));
// }
private PointLoader getPeakJumpLoader(Meta measurement) {
if (peakJumpLoader == null) {
try {
// StoragePlugin plugin = getContext().provide("storage", StoragePlugin.class);
Storage primaryStorage = getPrimaryStorage(measurement);
if (peakMap == null) {
throw new IllegalStateException("Peak map is not initialized");
}
DataFormatBuilder builder = new DataFormatBuilder().addTime("timestamp");
for (String peakName : this.peakMap.values()) {
builder.addNumber(peakName);
}
DataFormat format = builder.build();
//TODO Переделать!!!
String run = meta().getString("numass.run", "");
String suffix = Integer.toString((int) Instant.now().toEpochMilli());
peakJumpLoader = LoaderFactory
.buildPointLoder(primaryStorage, "msp" + suffix, run, "timestamp", format);
try {
Storage secondaryStorage = getSecondaryStorage(measurement);
if (secondaryStorage != null) {
PointLoader backupLoader = LoaderFactory
.buildPointLoder(secondaryStorage, "msp" + suffix, run, "timestamp", format);
peakJumpLoader = new ChainPointLoader(peakJumpLoader, backupLoader);
}
} catch (Exception ex) {
getLogger().error("Failed to initialize backup peak jump loader", ex);
}
} catch (StorageException ex) {
getLogger().error("Failed to initialize primary peak jump loader", ex);
return null;
}
}
return peakJumpLoader;
}
public void setListener(MspListener listener) {
@ -274,21 +245,22 @@ public class MspDevice extends SingleMeasurementDevice {
return new MspResponse(response);
}
public boolean isConnected() {
return getState("connected") != null && getState("connected").booleanValue();
}
public boolean isSelected() {
return isSelected;
return getState("selected") != null && getState("selected").booleanValue();
}
public boolean isControlled() {
return isControlled;
return getState("controlled") != null && getState("controlled").booleanValue();
}
public boolean isFilamentOn() {
return isFilamentOn;
return getState("filamentOn").booleanValue();
}
// public boolean isIsScanning() {
// return isScanning;
// }
/**
* Turn filament on or off
*
@ -305,59 +277,40 @@ public class MspDevice extends SingleMeasurementDevice {
}
}
// /**
// * Create measurement with parameters and return its name
// *
// * @param an
// * @return
// * @throws hep.dataforge.exceptions.PortException
// */
// private void createPeakJumpMeasurement(Meta an) throws ControlException {
// String name = "peakJump";//an.getString("measurementNAmname", "default");
// String filterMode = an.getString("filterMode", "PeakAverage");
// int accuracy = an.getInt("accuracy", 5);
// //PENDING вставить остальные параметры?
// sendAndWait("MeasurementRemove", name);
// if (sendAndWait("AddPeakJump", name, filterMode, accuracy, 0, 0, 0).isOK()) {
// peakMap = new LinkedHashMap<>();
// for (Meta peak : an.getNodes("peak")) {
// peakMap.put(peak.getInt("mass"), peak.getString("name", peak.getString("mass")));
// if (!sendAndWait("MeasurementAddMass", peak.getString("mass")).isOK()) {
// throw new ControlException("Can't add mass to measurement measurement for msp");
// }
// }
// } else {
// throw new ControlException("Can't create measurement for msp");
// }
// }
@Override
public void shutdown() throws ControlException {
super.shutdown();
super.stopMeasurement(true);
setFileamentOn(false);
sendAndWait("Release");
handler.close();
}
/**
* Evaluate general async messages
*
* @param response
*/
private void evaluateResponse(MspResponse response) {
}
@Override
public void accept(String message) {
if (mspListener != null) {
mspListener.acceptMessage(message.trim());
}
MspResponse response = new MspResponse(message);
switch (response.getCommandName()) {
// all possible async messages
case "FilamentStatus":
String status = response.get(0, 2);
isFilamentOn = status.equals("ON");
updateState("filamentOn", status.equals("ON"));
updateState("filamentStatus", status);
if (mspListener != null) {
mspListener.acceptFillamentStateChange(status);
}
break;
}
if (responseDelegate != null) {
responseDelegate.accept(response);
}
}
private void evaluateError(String errorMessage, Throwable error) {
@Override
public void error(String errorMessage, Throwable error) {
if (mspListener != null) {
mspListener.error(errorMessage, error);
} else if (error != null) {
@ -418,24 +371,50 @@ public class MspDevice extends SingleMeasurementDevice {
}
}
private class PeakJumpMeasurement extends AbstractMeasurement<DataPoint> implements PortHandler.PortController {
private class PeakJumpMeasurement extends AbstractMeasurement<DataPoint> {
private final Map<Integer, Double> measurement = new ConcurrentSkipListMap<>();
private Map<Integer, String> peakMap;
private List<PointLoader> loaders = new ArrayList<>();
private final Meta meta;
public PeakJumpMeasurement(Meta meta) {
this.meta = meta;
}
private void prepareLoaders() {
loaders = new ArrayList<>();
forEachTypedConnection("storage", StorageConnection.class, (StorageConnection con) -> {
try {
Storage storage = con.getStorage();
if (peakMap == null) {
throw new IllegalStateException("Peak map is not initialized");
}
DataFormatBuilder builder = new DataFormatBuilder().addTime("timestamp");
for (String peakName : this.peakMap.values()) {
builder.addNumber(peakName);
}
DataFormat format = builder.build();
//TODO Переделать!!!
String run = meta().getString("numass.run", "");
String suffix = Integer.toString((int) Instant.now().toEpochMilli());
PointLoader loader = LoaderFactory
.buildPointLoder(storage, "msp" + suffix, run, "timestamp", format);
loaders.add(loader);
} catch (StorageException ex) {
getLogger().error("Failed to initialize peak jump loader", ex);
}
});
}
@Override
public void start() {
try {
//Take control of port
handler.holdBy(this);
} catch (PortException ex) {
Logger.getLogger(MspDevice.class.getName()).log(Level.SEVERE, null, ex);
}
responseDelegate = this::eval;
try {
String name = "peakJump";//an.getString("measurementNAmname", "default");
@ -468,21 +447,22 @@ public class MspDevice extends SingleMeasurementDevice {
} catch (ControlException ex) {
onError(ex);
}
onStart();
}
@Override
public boolean stop(boolean force) {
handler.unholdBy(this);
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
public boolean stop(boolean force) throws MeasurementException {
try {
boolean stop = sendAndWait("ScanStop").isOK();
onStop();
responseDelegate = null;
return stop;
} catch (PortException ex) {
throw new MeasurementException(ex);
}
}
@Override
public void accept(String message) {
if (mspListener != null) {
mspListener.acceptMessage(message.trim());
}
MspResponse response = new MspResponse(message);
public void eval(MspResponse response) {
//Evaluating device state change
evaluateResponse(response);
@ -494,14 +474,11 @@ public class MspDevice extends SingleMeasurementDevice {
measurement.put((int) Math.floor(mass + 0.5), value);
break;
case "StartingScan":
if (mspListener != null && !measurement.isEmpty() && isFilamentOn) {
if (mspListener != null && !measurement.isEmpty()) {
if (peakMap == null) {
throw new IllegalStateException("Peal map is not initialized");
}
mspListener.acceptScan(measurement);
Instant time = Instant.now();
MapDataPoint point = new MapDataPoint();
@ -512,9 +489,12 @@ public class MspDevice extends SingleMeasurementDevice {
point.putValue(peakMap.get(entry.getKey()), val);
});
if (peakJumpLoader != null) {
if (isFilamentOn()) {
mspListener.acceptScan(measurement);
for (PointLoader loader : this.loaders) {
try {
peakJumpLoader.push(point);
loader.push(point);
} catch (StorageException ex) {
getLogger().error("Push to repo failed", ex);
}
@ -537,12 +517,8 @@ public class MspDevice extends SingleMeasurementDevice {
break;
}
}
public boolean stopMeasurement() throws PortException {
return sendAndWait("ScanStop").isOK();
}
@Override
public void error(String errorMessage, Throwable error) {
if (error == null) {
onError(new MeasurementException(errorMessage));

View File

@ -15,16 +15,16 @@
*/
package inr.numass.control.msp.fx;
import hep.dataforge.meta.Meta;
import hep.dataforge.meta.MetaBuilder;
import hep.dataforge.meta.ConfigChangeListener;
import hep.dataforge.meta.Configuration;
import hep.dataforge.context.Context;
import hep.dataforge.context.GlobalContext;
import hep.dataforge.data.MapDataPoint;
import hep.dataforge.exceptions.ControlException;
import hep.dataforge.exceptions.PortException;
import hep.dataforge.io.MetaFileReader;
import hep.dataforge.meta.ConfigChangeListener;
import hep.dataforge.meta.Configuration;
import hep.dataforge.meta.Meta;
import hep.dataforge.meta.MetaBuilder;
import hep.dataforge.plots.data.DynamicPlottable;
import hep.dataforge.plots.data.DynamicPlottableSet;
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
@ -155,7 +155,7 @@ public class MspViewController implements Initializable, MspListener {
try {
getDevice().setListener(this);
getDevice().init();
getDevice().startMeasurement("peakJump");
// getDevice().startMeasurement("peakJump");
} catch (ControlException ex) {
showError(String.format("Can't connect to %s:%d. The port is either busy or not the MKS mass-spectrometer port",
config.getString("connection.ip", "127.0.0.1"),
@ -186,11 +186,11 @@ public class MspViewController implements Initializable, MspListener {
public void initPlot() {
Meta plotConfig = new MetaBuilder("plotFrame")
.setNode(new MetaBuilder("yAxis")
.setValue("logAxis", true)
.setValue("type", "log")
.setValue("axisTitle", "partial pressure")
.setValue("axisUnits", "mbar")
)
.setValue("xAxis.timeAxis", true);
.setValue("xAxis.type", "time");
this.plotFrame = new JFreeChartFrame(mspName, plotConfig).display(plotPane);
updatePlot();
// this.plot = DynamicPlot.attachToFX(plotPane, new AnnotationBuilder("plot-config").putValue("logY", true).build());