001package org.vishia.inspcPC.accTarget;
002
003
004import java.util.ArrayList;
005import java.util.Arrays;
006import java.util.Deque;
007import java.util.EventObject;
008import java.util.Iterator;
009import java.util.LinkedList;
010import java.util.Map;
011import java.util.Set;
012import java.util.TreeMap;
013import java.util.concurrent.ConcurrentLinkedQueue;
014import java.util.concurrent.atomic.AtomicBoolean;
015
016import org.vishia.byteData.ByteDataAccessBase;
017import org.vishia.byteData.ByteDataAccessSimple;
018import org.vishia.byteData.VariableAccessArray_ifc;
019import org.vishia.communication.Address_InterProcessComm;
020import org.vishia.communication.InspcDataExchangeAccess;
021import org.vishia.communication.InterProcessComm;
022import org.vishia.communication.InterProcessComm_SocketImpl;
023import org.vishia.event.EventCmdtypeWithBackEvent;
024import org.vishia.event.EventTimeout;
025import org.vishia.event.EventTimerThread;
026import org.vishia.inspcPC.InspcAccessExecRxOrder_ifc;
027import org.vishia.inspcPC.InspcAccess_ifc;
028import org.vishia.inspcPC.InspcPlugUser_ifc;
029import org.vishia.inspcPC.InspcTargetAccessData;
030import org.vishia.inspcPC.mng.InspcMng;
031import org.vishia.inspcPC.mng.InspcStruct;
032import org.vishia.inspcPC.mng.InspcVariable;
033import org.vishia.inspectorTarget.InspcTelgInfoSet;
034import org.vishia.msgDispatch.LogMessage;
035import org.vishia.reflect.ClassJc;
036import org.vishia.states.StateMachine;
037import org.vishia.states.StateSimple;
038import org.vishia.util.Assert;
039import org.vishia.util.Debugutil;
040
041/**An instance of this class accesses one target device via InterProcessCommunication, usual Ethernet-Sockets.
042 * This class gets an opened {@link InterProcessComm} from its {@link InspcCommPort} aggregate. 
043 * The InspcCommPort has created a receiving thread.<br> 
044 * <img src="../../../../img/InspcTargetAccessor_omd.png"><br>Object model diagram:
045 * <ul>
046 * <li>The {@link InspcMng} knows one or more InspcTargetAccessor-instances, indicated by its name. 
047 *   The name of the target access is the first part of the data path to a target: <code>"name:path.in.target"</code>
048 * <li>Any of that InspcTargetAccessor handles the datagrams to and from one target.
049 * <li>More as one InspcTargetAccessor or all one can handle their communication via only one instance of {@link InspcCommPort}.
050 * <li>The InspcCommPort associates an {@link InterProcessComm} interface which is implemented by the {@link InterProcessComm_SocketImpl}
051 *   or maybe for a serial communication or Dual-Port-RAM or other. It means the communication connection to a target can be done
052 *   in several ways independent of the mission of this class. 
053 * </ul>  
054 * See also: <li><a href="../../../../../../Inspc/html/InspcComm.html">.../vishia/Inspc/InspcComm.html</href> or 
055 * <a href="http://www.vishia.org/Inspc/html/InspcComm.html">www.vishia.org/Inspc/InspcComm.html</href>
056 * <br><br>
057 * A send requests are invoked from the environment, it is the {@link InspcMng}. 
058 * <ul>
059 * <li>Firstly {@link #isOrSetReady(long)} is invoked to see whether a communication task is pending yet.
060 * <li>If a communication is pending for this target, new requests should be deferred.
061 * <li>If the communication hangs, {@link #isOrSetReady(long)} clears the communication to this target and returns true
062 *   if the given timeout is expired: It is possible to unplug a target - it does not answer - and plug again later. 
063 *   The target does not repeat the lost answers. But it is ready for new communication. The timeout should be a proper time for the target.
064 *   If it is to less, the target may prepare the answer yet in the moment and it is disturbed hectically. The timeout should be acceptable
065 *   for usage. About 5 seconds may be a proper value.
066 * <li>If the communication is not pending, {@link #isOrSetReady(long)} returns true.
067 * <li>Then some requests can be prepared by invocation of the methods of the {@link InspcAccess_ifc} <code>cmdGet/Set</code>.... 
068 *   With them one or more datagrams are prepared. 
069 * <li>The requests contain a callback reference to  a {@link InspcAccessExecRxOrder_ifc}. 
070 * Thats {@link InspcAccessExecRxOrder_ifc#execInspcRxOrder(org.vishia.communication.InspcDataExchangeAccess.Inspcitem, long, LogMessage, int)} 
071 * is executed if the response item is received. With the order-number-concept 
072 * see {@link InspcDataExchangeAccess.Inspcitem#getOrder()} the request and the response are associated together.  
073 * <li>At least {@link #cmdFinit()} should be invoked. That completes the one or last datagram and forces sending to the target.   
074 * </ul>
075 * The following sequence shows that. This sequence is executed in one thread for cyclic communication. 
076 * <pre>        
077 * InspcMng                  this                 txAccess   commPort     ipc
078 *  |                          |                                 |            |
079 *  ~                          ~                                 ~            ~
080 *  +procComm():               |                                 |            |
081 *  +--isOrSetReady(...)------>|                      |          |            | 
082 *  +--cmdGetSet...----------->|--->addChild--------->|          |            | 
083 *  +--isOrSetReady(...)------>|                      |          |            | 
084 *  +--cmdGetSet...----------->|--->addChild--------->|          |            | 
085 *  +--cmdGetSet...----------->|--->addChild--------->|          |            | 
086 *  +                          |--completeDatagram()->|          |            | 
087 *  +--cmdGetSet...----------->|--->addChild--------->|          |            | 
088 *  +--cmdGetSet...----------->|--->addChild--------->|          |            | 
089 *  +                          |                      |          |            | 
090 *  +-->cmdFinit()------------>|--completeDatagram()->|          |            | 
091 *  |                  [bTaskPending = true]                     |            | 
092 *  |                          |---send(txBuffer)--------------->|--send----->| 
093 *  |                          |                                 |            | 
094 *  ~                          ~                                 ~            ~ 
095 * </pre>
096 * Therewith up to 10 datagrams are assembled. Only the first datagram is sent yet. The target may answer:
097 * <ul>
098 * <li>An answer may need more as one answer datagram. 
099 *  The received datagrams are checked whether they have the correct sequence and answer number. Only then
100 *  they are stored in {@link #_tdata} {@link TelgData#rxDatagram}. This is done in {@link #evaluateRxTelg(byte[], int)}.
101 * <li>The answer datagrams don't need to receive in the correct order. There are filled some bits {@link TelgData#rxBitsAnswerNr}. 
102 *  An datagram which is received twice is ignored as twice.
103 * <li>The last answer datagram is marked with {@link InspcDataExchangeAccess.InspcDatagram#lastAnswer()}, a special bit. 
104 *  With them is can be recognized that all datagrams are completely received.
105 * </ul>
106 * <pre> 
107 *                           this                              commPort      ipc
108 *                             |                                 |            !
109 *                             ~                                 ~            ~<<==
110 *                             |                                 !            !   "
111 *                             !                                 !<..receive..!   "
112 *                 [rxDatagram]!<---evaluateRxTelg(datagram)-----!            !   "
113 *                 [rxDatagram]!<---evaluateRxTelg(datagram)-----!            !   "
114 *                             !                                 !            !   "
115 *                             ~                                 ~            ~   "
116 * </pre>
117 * <ul>
118 * <li>The cyclic {@link InspcMng#procComm()} invokes {@link #evaluateRxTelgInspcThread()} cyclically. This routine checks 
119 *   whether all datagrams of one request datagram are received. It invokes 
120 *   {@link #evaluateOneDatagram(org.vishia.communication.InspcDataExchangeAccess.InspcDatagram, InspcAccessExecRxOrder_ifc, long, LogMessage, int, DebugTxRx, int)}
121 *   internally for each of the received datagrams.
122 * <li>The data of the datagram are evaluated using the {@link InspcDataExchangeAccess.Inspcitem} for each item.
123 *   That is derived from {@link ByteDataAccessBase} which converts the byte data in the datagram to user specifics.
124 * <li>For each item the {@link InspcDataExchangeAccess.Inspcitem#getOrder()} is read. 
125 *  With them and the stored {@link InspcAccessExecRxOrder_ifc} is searched in the {@link #ordersExpected} index.
126 * <li>The {@link InspcAccessExecRxOrder_ifc#execInspcRxOrder(org.vishia.communication.InspcDataExchangeAccess.Inspcitem, long, LogMessage, int)}
127 *  is invoked with the received datagram item. That is the <b>callback to the users level</b> with the received information.     
128 * <li>If the datagram is evaluated, the routine {@link #evaluateRxTelgInspcThread()} looks whether a next datagram with assembled requests
129 *   are given furthermore. Then it sends is to the target.  
130 * <li>With a next {@link #send()} this sequence is repeated.
131 * </ul>
132 * <pre>
133 * InspcMng                  this                                                 "
134 *  |                          |                                                  "
135 *  ~                          ~                                                  "
136 *  +procComm():               |                                                  "
137 *  +-evalRxTelgInspcThread()->|[rxDatagram]
138 *  +                          |-evaluateOneDatagram()-+            Requestor     "              
139 *  +                          +<----------------------+                  |       "         
140 *  +                          +----execInspcRxOrder(datagramitem, ...)-->|       "                          
141 *  +                          +----execInspcRxOrder(datagramitem, ...)-->|       "                          
142 *  +                          +----execInspcRxOrder(datagramitem, ...)-->|       "                          
143 *  +                          +----execInspcRxOrder(datagramitem, ...)-->|       "                          
144 *  +                          +                                          |       "
145 *  +                          +                                                  "
146 *  +                          +                               commPort      ipc  "
147 *  +                          +                                 |            |   "
148 *  +                          +---send(txBuffer)--------------->|...........>|   "
149 *  +<.........................+                                 |            |   "
150 *  |                          |                                 |            |   "
151 *  |                          |                                 |            |   "
152 *  ~                          ~                                 ~            ~====
153 * </pre>
154 * The communication is still pending yet. Next requests from user level are deferred till this repetition
155 * of {@link #send()} and {@link #evaluateRxTelgInspcThread()} is currently.
156 * <br><br>
157 * If all datagrams are sent and all answers are received: 
158 *  <pre>
159 * InspcMng                  this                                                 "
160 *  |                          |                                                  "
161 *  ~                          ~                                 ~            ~
162 *  |                          |[on last datagram:    ]
163 *  |                          |[bTaskPending = false;]
164 *  |                          |
165 *  ~                          ~
166 *  |--isOrSetReady(...)------>|   //the next communication cycle
167 *  |                             
168 *  </pre>
169 * The cmdGetSet routines are:
170 * <ul>
171 * <li>{@link #cmdGetFields(String, InspcAccessExecRxOrder_ifc)}
172 * <li>{@link #cmdGetValueByPath(String, InspcAccessExecRxOrder_ifc)}
173 * <li>{@link #cmdRegisterHandle(String, InspcAccessExecRxOrder_ifc)}
174 * <li>{@link #cmdGetValueByHandle(int, InspcAccessExecRxOrder_ifc)}
175 * <li>{@link #cmdGetAddressByPath(String, InspcAccessExecRxOrder_ifc)}
176 * <li>{@link #cmdSetValueByPath(String, double, InspcAccessExecRxOrder_ifc)}
177 * <li>{@link #cmdSetValueByPath(String, float, InspcAccessExecRxOrder_ifc)}
178 * <li>{@link #cmdSetValueByPath(String, int, InspcAccessExecRxOrder_ifc)}
179 * <li>{@link #cmdSetValueByPath(String, long, int, InspcAccessExecRxOrder_ifc)}
180 * </ul>
181 * The routines organizes the datagram. If one datagram is full, the next instance is used. There are 10 instances
182 * of {@link TxBuffer}.
183 * <br><br>
184 * At least the user should invoke {@link #cmdFinit()}. That command completes the only one or the last datagram
185 * and sends the first datagram to the target. With this invocation the {@link #isReady(long)} returns false
186 * because the variable {@link #bTaskPending} is set to true.
187 * <br><br>
188 * The target should response with the answer with the same sequence number to associate answer and request. 
189 * The {@link #commPort} ({@link InspcCommPort}) gets the received telegram.
190 * On comparison of the sender address in the datagram or on comparison of the entrant in the 
191 * datagram's head {@link InspcDataExchangeAccess.InspcDatagram#getEntrant()}.
192 * The answer from target can consist of more as one datagram. Any correct answer telegram invokes 
193 * {@link #evaluateRxTelg(byte[], int)}. 
194 * The answer contains some {@link InspcDataExchangeAccess.Inspcitem}. All of them has its order number. 
195 * With the order number the associated {@link InspcAccessExecRxOrder_ifc
196 * #execInspcRxOrder(org.vishia.communication.InspcDataExchangeAccess.Inspcitem, long, LogMessage, int)}
197 * is invoked as callback in the users space. This is organized in the aggregated {@link #rxEval} instance.   
198 * <br><br>
199 * If the last answer datagram of a request is gotten, the next datagram  of this task will be sent to the target. The target
200 * will be attacked only by one telegram in one time, all one after another. That is because a target may have
201 * less network resources (a cheap processor etc.). After the last receive datagram of the last send datagram
202 * the semaphore {@link #bTaskPending} is set to false, a next {@link #isReady(long)} returns true 
203 * for the next task of requests. 
204 * <br><br>
205 * On receive the {@link #commPort} ({@link InspcCommPort}) gets the received telegram.
206 * On comparison of the sender address in the datagram or on comparison of the entrant in the 
207 * datagram's head {@link InspcDataExchangeAccess.InspcDatagram#getEntrant()}.
208 * <br><br>
209 * <b>Requests in multithreading</b><br>
210 * The routines {@link #cmdGetValueByPath(String, InspcAccessExecRxOrder_ifc)} etc. are not threadsafe.
211 * That is because the organization of a datagram content should be controlled by one hand. Typically this 
212 * only one thread runs cyclically because it requests currently data.
213 * <br>
214 * To support requests in more as one thread two strategies are supported:
215 * <ul>
216 * <li>A thread can assemble its own datagram and then add to the cyclic communication thread.
217 * <li>A thread can invoke simple request items which are stored in a {@link ConcurrentLinkedQueue} and 
218 *   regarded on next cyclic call.
219 * </ul>
220 * In both cases the {@link InspcAccessExecRxOrder_ifc
221 * #execInspcRxOrder(org.vishia.communication.InspcDataExchangeAccess.Inspcitem, long, LogMessage, int)}
222 * is invoked by the receiver's thread called back in the user's space. This routines can be used to notify
223 * any waiting thread or any short action can be done in the callback, especially request of some more cmd...    
224 * @author Hartmut Schorrig
225 *
226 */
227@SuppressWarnings("synthetic-access") 
228public class InspcTargetAccessor implements InspcAccess_ifc
229{
230        
231  /**The version history and license of this class.
232   * <ul>
233   * <li>2015-10-29 Hartmut chg: {@link #isOrSetReady(long)} now checks the timeout by its own {@link #cycle_timeout}.
234   *   The last one can be changed in the {@link #setStateToUser(InspcPlugUser_ifc)} which acts with the graphical user interface.
235   *   Therewith the timeout can be changed in the GUI especially for debugging situations.
236   * <li>2015-08-08 Hartmut chg: getValueByHandle now works. Some changes. 
237   * <li>2015-06-24 Hartmut chg: Writing debug info for all tx and rx items is able to disable. 
238   * <li>2015-06-21 Hartmut chg: Now getFields set the {@link GetFieldsData#bGetFieldsPending} and prohibits further telegrams
239   *   via {@link #isOrSetReady(long)} false-return: Reason: The target does not regard a new telegram
240   *   for further get-value requests if the telegram has less free space. The target crashes instead. 
241   *   On getFields more as one answer telegram is regarded. But the rest of the telegram for getValueByPath does not work. 
242   *   An older non fixed target should be accepted because it runs in field - no update possibility!   
243   * <li>2015-05-28 Hartmut new {@link #addUserTxOrder(Runnable)} not only for the whole {@link InspcMng}.
244   * <li>2015-05-28 Hartmut bugfix length of item was faulty for #cmdSetValueByPath(...). 
245   *   Check length in {@link InspcTelgInfoSet#lengthCmdSetValueByPath(int)}. For all commands.
246   * <li>2015-05-20 Hartmut new {@link DebugTxRx}, data in sub classes 
247   * <li>2015-03-20 Hartmut {@link #requestFields(InspcStruct, Runnable)} redesigned 
248   * <li>2014-10-12 Hartmut State machine included, tested but not active used. 
249   * <li>2014-09-21 Hartmut TODO use a state machine .
250   * <li>2014-01-08 Hartmut chg: {@link #cmdSetValueByPath(String, int, InspcAccessExecRxOrder_ifc)},
251   *   {@link #valueStringFromRxValue(org.vishia.communication.InspcDataExchangeAccess.Inspcitem, int)}
252   * <li>2014-01-08 Hartmut chg: Now change of time regime. The request thread writes only data 
253   *   and invokes the first send. All other communication is done in the receive thread. 
254   *   The goal is: The target system should gotten only one telegram at one time, all telegrams one after another.
255   * <li>2012-04-08 Hartmut new: Support of GetValueByIdent
256   * <li>2012-04-05 Hartmut new: Use {@link LogMessage to test telegram traffic}
257   * <li>2012-04-02 Hartmut new: {@link #sendAndPrepareCmdSetValueByPath(String, long, int, InspcAccessExecRxOrder_ifc)}.
258   *   The concept is: provide the {@link InspcAccessExecRxOrder_ifc} with the send request.
259   *   It should be implement for all requests in this form. But the awaiting of answer doesn't may the best way.
260   *   Problem evaluating the answer telg in the rx thread or in the tx thread. TODO documentation.
261   * <li>2011-06-19 Hartmut new; {@link #shouldSend()} and {@link #isFilledTxTelg()} able to call outside.
262   *     It improves the handling with info blocks in a telegram.
263   * <li>2011-05 Hartmut created
264   * </ul>
265   * <br><br>
266   * <b>Copyright/Copyleft</b>:
267   * For this source the LGPL Lesser General Public License,
268   * published by the Free Software Foundation is valid.
269   * It means:
270   * <ol>
271   * <li> You can use this source without any restriction for any desired purpose.
272   * <li> You can redistribute copies of this source to everybody.
273   * <li> Every user of this source, also the user of redistribute copies
274   *    with or without payment, must accept this license for further using.
275   * <li> But the LPGL ist not appropriate for a whole software product,
276   *    if this source is only a part of them. It means, the user
277   *    must publish this part of source,
278   *    but don't need to publish the whole source of the own product.
279   * <li> You can study and modify (improve) this source
280   *    for own using or for redistribution, but you have to license the
281   *    modified sources likewise under this LGPL Lesser General Public License.
282   *    You mustn't delete this Copyright/Copyleft inscription in this source file.
283   * </ol>
284   * If you are intent to use this sources without publishing its usage, you can get
285   * a second license subscribing a special contract with the author. 
286   * 
287   * @author Hartmut Schorrig = hartmut.schorrig@vishia.de
288   */
289  final static String version = "2015-08-08";
290
291  private static class DebugTxRx{ 
292    //int[] posTelgItems = new int[200];
293    int nrofBytesDatagramReceived;
294    int nrofBytesDatagramInHead;
295    /**The last send tx telegram. */
296    InspcDataExchangeAccess.InspcDatagram txTelgHead; ////
297    ArrayList<InspcDataExchangeAccess.Inspcitem> txItems;
298    
299    /**All received answerNr telegrams for the last send tx telegram. The received telegrams for older tx telegrams are removed. */
300    InspcDataExchangeAccess.InspcDatagram[] rxTelgHead = new InspcDataExchangeAccess.InspcDatagram[20]; ////
301    
302    /**All received items for the rx telegrams of one tx telegram. */
303    ArrayList<InspcDataExchangeAccess.Inspcitem>[] rxItems = new ArrayList[20];  //for up to 20 received telegrams.
304    
305    
306    @SuppressWarnings("unchecked") 
307    DebugTxRx() {
308      txItems = new ArrayList<InspcDataExchangeAccess.Inspcitem>();
309      for(int ix = 0; ix < rxItems.length; ++ix){
310        rxItems[ix] = new ArrayList<InspcDataExchangeAccess.Inspcitem>();
311      }
312    }
313    
314    
315    /**Removes all rx data, so that the garbage collector can garbage it.
316     * Called on #isOrSetReady if ready.
317     */
318    void clearAll() {
319      if(txTelgHead != null){ txTelgHead.removeChildren(); }
320      txItems.clear();
321      clearRx();
322     }
323
324    /**Removes all rx data, so that the garbage collector can garbage it.
325     * Called on #isOrSetReady if ready.
326     */
327    void clearRx() {
328      for(int ix = 0; ix < rxItems.length; ++ix){
329        if(rxTelgHead[ix] != null){ 
330          rxTelgHead[ix].removeChildren(); 
331          rxTelgHead[ix] = null;
332        }
333        rxItems[ix].clear(); //the children items
334      }
335      nrofBytesDatagramInHead = -1;
336      nrofBytesDatagramReceived = -1;
337
338    }
339  }
340
341  
342  /**This class contains all data for one datagram to send.
343   * @author hartmut
344   *
345   */
346  private class TxBuffer
347  {
348    byte[] buffer;
349    
350    TxBuffer(){}
351    int nSeq;
352    int nrofBytesTelg;
353    //AtomicInteger stateOfTxTelg = new AtomicInteger();
354    boolean lastTelg;
355  }
356  
357  private static class OrderWithTime
358  {
359    final int order;
360    final long time;
361    final InspcAccessExecRxOrder_ifc exec;
362    
363    public OrderWithTime(int order, long time, InspcAccessExecRxOrder_ifc exec)
364    { this.order = order;
365      this.time = time;
366      this.exec = exec;
367    }
368    
369  }
370  
371
372  
373  private static class TelgData
374  {
375    boolean bDebugTelg = true;
376    
377    /**Position of all received items.
378     * 
379     */
380    DebugTxRx[] debugTxRx = new DebugTxRx[10];
381    
382    /**The current used sequence number. It is never 0 if it is used the first time. */
383    int nSeqNumber = 600;
384
385    /**The sequence number for that datagram which is send and await to receive.
386     * Note that the target can send more as one answer telegram for one request.
387     * All answers has the same sequence number, but they have different answer numbers. 
388     */
389    int nSeqNumberTxRx;
390
391    private final TxBuffer[] tx = new TxBuffer[10];
392    
393    /**Index for {@link #txBuffer} for the currently filled buffer. */
394    private int txixFill = 0;
395    
396    /**Index for {@link #txBuffer} for the buffer which should be send if it is full. */
397    private int txixSend = 0;
398
399    /**The start answer number is 1 for newer datagrams but 0 for older ones. If an answer with 0 is received one time, 
400     * it is set to 0 for that target for ever because it is an old one.
401     */
402    //int startAnswerNr = 1;
403    /**The old target starts the answers from 0 and has a step by 2. It is detect because the first answer as {@link InspcDataExchangeAccess.InspcDatagram#getAnswerNr()} ==0*/
404    boolean oldTarget;
405    
406    /**Up to 64 answer numbers which are received already for the request.
407     * A twice received answer is not evaluated twice. Note that in network communication
408     * any telegram can received more as one time with the same content.
409     */
410    long rxBitsAnswerNr;
411
412    long rxBitsAnswerMask;
413
414    /**Up to 128 receive buffers for all datagrams for this sequence number, there may be more as one answer per request. */
415    InspcDataExchangeAccess.InspcDatagram[] rxDatagram = new InspcDataExchangeAccess.InspcDatagram[128];
416
417    /**Number of received datagrams for 1 sequence. */
418    int rxNrofDatagramsForOneSend; 
419    
420    
421    final InspcDataExchangeAccess.InspcDatagram accTxTelgStatic = new InspcDataExchangeAccess.InspcDatagram();
422    
423    final InspcTelgInfoSet accTxItemStatic = new InspcTelgInfoSet();
424    
425    final InspcDataExchangeAccess.InspcDatagram accRxTelgStatic = new InspcDataExchangeAccess.InspcDatagram();
426    
427    final InspcDataExchangeAccess.Inspcitem accRxItemStatic = new InspcDataExchangeAccess.Inspcitem();
428  }
429  
430  TelgData _tdata = new TelgData();
431  
432  private static class GetFieldsData
433  {
434
435    /**If not null then cmdGetFields will be invoked in the next {@link InspcTargetAccessor#cmdFinit()} invocation.
436     * After them this field will be set to null again. */
437    InspcTargetAccessData requFields;
438    
439    /**Action on receiving fields from target, only valid for the requFields. */
440    InspcAccessExecRxOrder_ifc rxActionGetFields;
441    
442    /**If not null then this runnable will be called on end of requestFields. */
443    Runnable runOnResponseFields;
444    
445    /**The last order for Get Fields.
446     * Special case: Only this telegram-info has more as one answer.
447     * Only one request 'get fields' should be send in one time.
448     * This order will be set on the first answer 'get fields' and remain for more answers.
449     * The next request 'get fields' will be received with the first field with another order,
450     * which is stored here etc.
451     */
452    OrderWithTime orderGetFields;
453
454    private boolean bGetFieldsPending;
455    
456  } GetFieldsData getFieldsData = new GetFieldsData();
457  
458  
459  /**Identifier especially for debugging. */
460  final String name;
461  
462  /**Free String to write, for debug stop. */
463  String dbgNameStopTx;
464
465  /**If true then writes a log of all send and received telegrams. */
466  LogMessage logTelg;
467  
468  boolean bWriteDebugSystemOut;  //if(logTelg !=null && bWriteDebugSystemOut)
469  
470  int identLogTelg;
471  
472        private final InspcAccessGenerateOrder orderGenerator = new InspcAccessGenerateOrder();
473        
474        
475  
476 //private final InspcAccessCheckerRxTelg checkerRxTelg = new InspcAccessCheckerRxTelg();
477        
478  /**Map of all orders which are send as request.
479   * 
480   */
481  protected final Map<Integer, OrderWithTime> ordersExpected = new TreeMap<Integer, OrderWithTime>();
482  
483  
484  final Deque<OrderWithTime> listTimedOrders = new LinkedList<OrderWithTime>();
485  
486  /**Some orders from any application which should be run in the {@link #inspcThread}. */
487  private final ConcurrentLinkedQueue<Runnable> userTxOrders = new ConcurrentLinkedQueue<Runnable>();
488  
489
490  
491  /**Map of all Variables which are gotten by handle.
492   * 
493   */
494  final Map<Integer, InspcVariable> XXXvariablesByHandle = new TreeMap<Integer, InspcVariable>();
495  
496  
497  /**Reused instance to evaluate any info blocks.
498   * 
499   */
500  //InspcDataExchangeAccess.Inspcitem infoAccessRx = new InspcDataExchangeAccess.Inspcitem();
501  
502  
503
504  
505  public final Map<Integer, Runnable> callbacksOnAnswer = new TreeMap<Integer, Runnable>();
506  
507
508  char state = 'R';
509  
510
511  
512  final States states;
513  
514  
515  private final StateSimple stateIdle, stateWaitAnswer;
516  
517  enum Cmd{ fill, send, lastAnswer};
518  
519  class Ev extends EventCmdtypeWithBackEvent<Cmd, Ev>{ Ev(Cmd cmd){ super(cmd); } };
520  
521  Ev evFill = new Ev(Cmd.fill);
522  
523  Ev evSend = new Ev(Cmd.send);
524  
525  Ev evLastAnswer = new Ev(Cmd.lastAnswer);
526  
527
528  
529  
530  class States extends StateMachine
531  {
532    
533    States(EventTimerThread thread){ super("InspcTargetAccessor", thread); }
534    
535    
536    class StateInactive extends StateSimple {
537      final boolean isDefault = true;
538
539      Trans addRequest_Filling(EventObject ev, Trans trans)
540      {
541        if(trans ==null) return new Trans(StateFilling.class);
542        if(ev == evFill){
543          trans.retTrans = mTransit | mEventConsumed;
544          trans.doExit();
545          trans.doEntry(ev); 
546        } 
547        return trans;
548      }
549    
550      
551    };
552    
553    
554    class StateIdle extends StateSimple {
555   
556      @Override public int entry(EventObject ev){
557        //stateMachine.timeout(System.currentTimeMillis() + 10000);
558        return 0;
559      }
560      
561      Timeout timeout = new Timeout(10000, StateInactive.class);
562      
563      Trans addRequest_Filling = new Trans(StateFilling.class);
564    
565      @Override protected Trans checkTrans(EventObject ev){
566        if(ev instanceof EventTimeout) return timeout;
567        else if(ev == evFill) return addRequest_Filling;
568        else return null;
569      }
570
571    };
572    
573    
574    class StateFilling extends StateSimple {
575      //StateSimple stateFilling = new StateSimple(states, "filling"){
576
577      Trans addRequest = new Trans(StateFilling.class); //remain in state
578  
579      Trans shouldSend_WaitReceive = new Trans(StateWaitReceive.class);
580    
581      @Override protected Trans checkTrans(EventObject ev){
582        if(ev == evFill) return addRequest;
583        else if(ev == evSend) return shouldSend_WaitReceive;
584        else return null;
585      }
586      
587    };
588    
589    
590    
591    class StateWaitReceive extends StateSimple {
592      //StateSimple stateSending = new StateSimple(states, "sending"){
593
594      @Override public int entry(EventObject ev) {
595        timeSend = System.currentTimeMillis(); 
596        return 0;
597      }
598      
599      Trans lastAnswer_WaitReceive(EventObject ev, Trans trans)
600      {
601        if(trans ==null) return new Trans(StateIdle.class);
602        if(ev == evLastAnswer){
603          trans.retTrans = mTransit | mEventConsumed;
604          trans.doExit();
605          trans.doEntry(ev); 
606        } 
607        return trans;
608      }
609      
610    };
611    
612    
613    
614    class StateReceive extends StateSimple {
615    //StateSimple stateWaitAnswer = new StateSimple(states, "waitAnswer"){
616
617      Trans lastAnswer_Idle = new Trans(StateIdle.class);
618    
619      Trans notLastAnswer_WaitReceive = new Trans(StateReceive.class);
620      
621    };
622    
623    
624 
625    
626    
627    
628    
629  }
630  
631  
632  //States states1 = new States();
633  
634  
635  //final StateTop states = new StateTop(null);
636  
637  
638  
639  
640  
641        /**If true, then a TelgHead is prepared already and some more info can be taken into the telegram.
642         * If false then the txBuffer is unused yet.
643         */
644        private boolean bFillTelg = false;
645        
646        /**If true then the current prepared tx telegram should be send.
647         * This bit is set, if a info block can't be placed in the current telegram.
648         */
649  private boolean bShouldSend = false;
650        
651        /**True if a second datagram is prepared and sent yet.
652   * 
653   */
654  private boolean bIsSentTelg = false;
655  
656  
657  /**True if it is sent and not all answers are received yet. */
658  //private final AtomicBoolean bSendPending = new AtomicBoolean();
659  
660  
661  /**Set if the {@link #cmdFinit()} is given. set false on last received answer for the task. */
662  private final AtomicBoolean bTaskPending = new AtomicBoolean();
663  
664  private boolean bRequestWhileTaskPending;
665  
666        long timeSend, timeReceive, dtimeReceive, dtimeWeakup;
667        
668        /**Set to true while a telegram is evaluating in the received thread.
669         * Then {@link #isOrSetReady(long)} returns false though the time is expired.  
670         * This is a helper for debugging firstly. Don't send new telegrams while debugging.
671         */
672        boolean bRunInRxThread;
673        
674        private InspcDataExchangeAccess.InspcDatagram txAccess;
675        
676        
677        /**Number of idents to get values per ident. It determines the length of an info block,
678         * see {@link #dataInfoDataGetValueByIdent}. An info block has to be no longer than a UDP-telegram.
679         */
680        private final static int zIdent4GetValueByIdent = 300;  //1200 Byte
681        
682        private int ixIdent5GetValueByIdent;
683        
684        /**A info element to get values by ident It contains a {@link InspcDataExchangeAccess.Inspcitem} head
685         * and then 4-byte-idents for data. The same order of data are given in the array
686         */
687        private final byte[] dataInfoDataGetValueByIdent = new byte[InspcDataExchangeAccess.Inspcitem.sizeofHead + 4 * zIdent4GetValueByIdent]; 
688        
689        
690        //ByteBuffer acc4ValueByIdent = new ByteBuffer();
691        
692        /**Managing instance of {@link ByteDataAccessBase} for {@link #dataInfoDataGetValueByIdent}. */
693        private final ByteDataAccessBase accInfoDataGetValueByIdent;
694        
695        private final InspcAccessExecRxOrder_ifc[] actionRx4GetValueByHandle = new InspcAccessExecRxOrder_ifc[zIdent4GetValueByIdent]; 
696        //InspcVariable[] variable4GetValueByIdent = new InspcVariable[zIdent4GetValueByIdent];
697        
698        /**The entrant is the sub-consumer of a telegram on the device with given IP.
699         * A negative number is need because compatibility with oder telegram structures.
700         * The correct number depends on the device. It is a user parameter of connection.
701         */
702        int nEntrant = -1;
703        
704        final Address_InterProcessComm targetAddr;
705        
706        int nEncryption = 0;
707        
708  private final InspcCommPort commPort; 
709        
710  
711  final float[] cycle_timeout = new float[2];
712  
713  
714  public InspcTargetAccessor(String name, InspcCommPort commPort, Address_InterProcessComm targetAddr, EventTimerThread threadEvents)
715  { this.name = name;
716    this.commPort = commPort;
717    this.targetAddr = targetAddr;
718    cycle_timeout[0] = 0.1f;
719    cycle_timeout[1] = 5.0f;
720    accInfoDataGetValueByIdent = new ByteDataAccessBase(0);
721    accInfoDataGetValueByIdent.setBigEndian(true);
722    accInfoDataGetValueByIdent.assignClear(dataInfoDataGetValueByIdent);
723    //this.infoAccess = new InspcTelgInfoSet();
724    for(int ix = 0; ix < _tdata.tx.length; ++ix){
725      _tdata.tx[ix] = new TxBuffer();
726      _tdata.tx[ix].buffer = new byte[1400];
727      //tx[ix].stateOfTxTelg.set(0);
728    }
729    for(int ix1 = 0; ix1 < _tdata.debugTxRx.length; ++ix1) {
730        DebugTxRx debugData = _tdata.debugTxRx[ix1] = new DebugTxRx(); //only initially.
731        //Arrays.fill(debugData.posTelgItems, -1);  
732        debugData.clearAll();
733    }
734
735    commPort.registerTargetAccessor(this);
736    states = new States(threadEvents);  
737    stateIdle = states.getState(States.StateIdle.class);
738    stateWaitAnswer = states.getState(States.StateWaitReceive.class);
739    //The factory should be loaded already. Then the instance is able to get. Loaded before!
740  }
741
742        
743        /**Sets the target address for the next telegram assembling and the next send()-invocation.
744         * If a telegram is pending, it will be sent. A new telegram is prepared.
745         * @param sTargetIpAddr
746         */
747        @Deprecated
748        public void setTargetAddr(String sTargetIpAddr)
749        { //TODO check and send, prepare new head.
750          //this.sTargetIpAddr = sTargetIpAddr;
751          //this.targetAddr = new Address_InterProcessComm_Socket(sTargetIpAddr);
752    //commPort.registerTargetAccessor(this);
753          assert(false);
754        }
755        
756        
757        
758        /**Switch on or off the log functionality.
759         * @param logP The log output. null then switch of the log.
760         * @param ident The ident number in log for send, next number for receive.
761         */
762        public void setLog(LogMessage log, int ident){
763          this.logTelg = log;
764          this.identLogTelg = ident;
765        }
766        
767        
768  /**Adds any program snippet which is executed while preparing the telegram for data request from target.
769   * After execution the order will be removed.
770   * @param order the program snippet.
771   */
772  public void addUserTxOrder(Runnable order)
773  {
774    userTxOrders.add(order);
775  }
776  
777
778  
779  /**Checks whether the head of the datagram should be created and the telegram has place for the current data.
780   * This routine is called at begin of all cmd...() routines of this class. 
781   * <ul>
782   * <li>Creates the head if if necessary.
783   * <li>Sets {@link #bFillTelg}, able to query with {@link isFilledTxTelg()}.
784   * <li>Checks whether the requested bytes are able to fill in the telegram.
785   * <li>Sets {@link #bShouldSend} able to query with {@link shouldSend()} if the info doesn't fit in the telegram.
786   * </ul>
787   * @param zBytesInfo Number of bytes to add to the telegram.
788   * @return true if the number of bytes are able to place in the current telegram.
789   *         If this routine returns false, the info can't be place in this telegram.
790   *         It should be send firstly. The current order should be processed after them.
791   */
792  private boolean prepareTelg(int lengthNewInfo)
793  { if(evFill.occupy(null, false)) {
794      states.processEvent(evFill);    //set state to fill
795    } else; //don't send the event, it is in queue already from last prepareTelg invocation.
796    if(!states.isInState(States.StateFilling.class)){
797      stop();
798    }
799    if(_tdata.txixFill >= _tdata.tx.length ){ //check more as one datagram
800      System.err.println("InspcTargetAccessor - Too many telegram requests;");
801      return false;
802    }
803    if(bFillTelg && (txAccess.getLengthTotal() + lengthNewInfo) > _tdata.tx[_tdata.txixFill].buffer.length){
804      //the next requested info does not fit in the current telg. 
805      //Therefore send the telg but only if the other telgs are received already!
806      completeDatagram(false);
807      if((_tdata.txixFill) >= _tdata.tx.length){
808        return false;   //not enough space for communication. 
809      }
810    }
811    if(!bFillTelg){
812      //assert(tx[ixTxFill].stateOfTxTelg.compareAndSet(0, 'f'));
813      //prepare a new telegram to send with ByteDataAccess, new head.
814      Arrays.fill(_tdata.tx[_tdata.txixFill].buffer, (byte)0);
815      if(_tdata.bDebugTelg) {
816        txAccess = new InspcDataExchangeAccess.InspcDatagram();
817        _tdata.debugTxRx[_tdata.txixFill].txTelgHead = txAccess;   //register in debug.
818      } else {
819        txAccess = _tdata.accTxTelgStatic;
820      }
821      txAccess.assignClear(_tdata.tx[_tdata.txixFill].buffer);
822      if(++_tdata.nSeqNumber == 0){ _tdata.nSeqNumber = 1; }
823      txAccess.setHeadRequest(nEntrant, _tdata.nSeqNumber, nEncryption);
824      bFillTelg = true;
825      if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - Prepare head; " + _tdata.txixFill + "; seq=" + _tdata.nSeqNumber);
826      int nRestBytes = _tdata.tx[_tdata.txixFill].buffer.length - txAccess.getLengthHead();
827      return true;
828    }
829    int lengthDatagram = txAccess.getLengthTotal();
830    
831    int nRestBytes = _tdata.tx[_tdata.txixFill].buffer.length - lengthDatagram;
832    return true;
833  }
834  
835        /**Returns true if enough information blocks are given, so that a telegram was sent already.
836         * A second telegram may be started to prepare with the last call. 
837         * But it should be waited for the answer firstly.  
838         * @return true if a telegram is sent but the answer isn't received yet.
839         */
840        public boolean checkIsSent()
841        {
842          return bIsSentTelg;
843        }
844        
845        
846        /**Checks readiness of communication cycle. Returns true if a communication cycle is not pending (finished).
847         * It is in state {@link States.StateIdle} or {@link States.StateFilling}
848         * Returns false if not all answer telegrams were received from the last request.
849         * It is in all other states of {@link States}. 
850         * If the time of the last send request was before timeLastTxWaitFor 
851         * then it is assumed that the communication was faulty. Therefore all older pending requests are removed.
852         * @param timeCurrent The current time. It is compared with the time of the last transmit telegram which's answer is expected,
853         *   and the timeout. If the timeout is expired, older requests are removed and this routine returns true. 
854         */
855        public boolean isOrSetReady(long timeCurrent){ 
856          boolean bReady;
857          if(!bTaskPending.get()){
858            bReady = !getFieldsData.bGetFieldsPending; //true;
859          }
860          else {
861            long timeLastTxWaitFor = timeCurrent - (long)(1000 * cycle_timeout[1]);
862            long dtimeExpired = timeLastTxWaitFor - timeSend;  //timeExpired is the timeLast - wait time 
863            if(  timeSend ==0  //a telegram was never sent, faulty bTaskPending 
864              || dtimeExpired >=0 && !bRunInRxThread
865              ) { //not ready for a longer time: 
866              //forgot a pending request:
867          //if(logTelg !=null) 
868        System.err.println("InspcTargetAccessor.isReady - recover after timeout target; " + toString());
869        bRequestWhileTaskPending = false;
870        synchronized(this){
871          Debugutil.stop();  //possibility to wait in debug
872              }
873        setReady();
874              bReady = true;  //is setted ready.
875            } else {
876              if(!bRequestWhileTaskPending){ //it is the first one
877                bRequestWhileTaskPending = true;
878                if(logTelg !=null) System.err.println("InspcTargetAccessor.isReady - not ready for requests; " + toString());
879              }
880              bReady = false; //not ready
881            }
882          }
883          if(bReady) {
884          }
885          return bReady;
886        }
887        
888        
889        /**Sets the communication cycle of ready (idle) state,
890         * called either inside {@link #isOrSetReady(long)} on time expired or if the last rx telegram was processed successfully.
891         */
892        private void setReady()
893        {
894    for(int ixRx = 0; ixRx < _tdata.rxNrofDatagramsForOneSend; ++ixRx) {
895      _tdata.rxDatagram [ixRx] = null;  //garbage it.
896    }
897    _tdata.rxNrofDatagramsForOneSend = 0;
898    _tdata.rxBitsAnswerNr = _tdata.rxBitsAnswerMask = 0;
899    state = 'R';
900    _tdata.txixSend = 0;
901    _tdata.txixFill = 0;   //if the last one was received, the tx-buffer is free for new requests. 
902    _tdata.nSeqNumberTxRx = 0;
903    getFieldsData.bGetFieldsPending = false;
904    bFillTelg = false;
905    bShouldSend = false;
906    bIsSentTelg = false;
907    //bSendPending.set(false);
908    ordersExpected.clear();  //after long waiting their is not any expected.
909    for(DebugTxRx debugData1: _tdata.debugTxRx) {
910      debugData1.clearAll();
911    }
912    bTaskPending.set(false);
913        }
914        
915        
916        
917  /**Sets an expected order in the index of orders and registers a callback after all telegrams was received if given.
918   * @param order The unique order number.
919   * @param exec The execution for the answer. 
920   */
921  public void setExpectedOrder(int order, InspcAccessExecRxOrder_ifc actionOnRx)
922  {
923    if(actionOnRx !=null){
924      OrderWithTime timedOrder = new OrderWithTime(order, System.currentTimeMillis(), actionOnRx);
925      //listTimedOrders.addFirst(timedOrder);
926      ordersExpected.put(new Integer(order), timedOrder);
927      Runnable action = actionOnRx.callbackOnAnswer();
928      if(action !=null){
929        callbacksOnAnswer.put(new Integer(action.hashCode()), action);  //register the same action only one time.
930      }
931    }
932  }
933  
934  
935  
936  
937  /**Set the request for all fields of the given variable. This method is invoked from outer (GUI) 
938   * to force {@link #cmdGetFields(String, InspcAccessExecRxOrder_ifc)} in the inspector thread.
939   * @param data The variable
940   * @param rxActionGetFields Action on gotten fields
941   * @param runOnReceive Action should be run if all fields are received, if all datagrams are received for that communication cycle.
942   */
943  public void requestFields(InspcTargetAccessData data, InspcAccessExecRxOrder_ifc rxActionGetFields, Runnable runOnReceive){
944    getFieldsData.rxActionGetFields = rxActionGetFields;
945    getFieldsData.runOnResponseFields = runOnReceive;
946    getFieldsData.requFields = data;  //this is the atomic signal to execute cmdGetFields
947  }
948
949  
950
951  InspcTelgInfoSet newTxitem(){
952    if(_tdata.bDebugTelg) {
953      InspcTelgInfoSet item = new InspcTelgInfoSet();
954      //register it in the debug struct
955      _tdata.debugTxRx[_tdata.txixFill].txItems.add(item);
956      return item;
957    } else {
958      _tdata.accRxItemStatic.detach();  //if it was used.
959      return _tdata.accTxItemStatic;
960    }
961  }
962  
963
964  /**Adds the info block to send 'get fields by path'
965   * @param sPathInTarget The path in the target with the target specific rules.
966   * @param actionOnRx this action will be executed on receiving the item.
967   * @return The order number. 0 if the cmd can't be created.
968   */
969  @Override public int cmdGetFields(String sPathInTarget, InspcAccessExecRxOrder_ifc actionOnRx)
970  { int order;
971    //states.applyEvent(evFill);
972    //if(states.isInState(stateFilling))
973      stop();
974    int lengthItem = InspcTelgInfoSet.lengthCmdGetFields(sPathInTarget.length());
975    if(prepareTelg(lengthItem)) {
976      //InspcTelgInfoSet infoGetValue = new InspcTelgInfoSet();
977      InspcTelgInfoSet infoAccess = newTxitem();
978      txAccess.addChild(infoAccess);
979      order = orderGenerator.getNewOrder();
980      infoAccess.setCmdGetFields(sPathInTarget, order);
981      if(logTelg !=null){ 
982        logTelg.sendMsg(identLogTelg+idLogGetFields, "add cmdGetFields %s, order = %d", sPathInTarget, new Integer(order)); 
983      }
984      getFieldsData.orderGetFields = new OrderWithTime(order, System.currentTimeMillis(), actionOnRx);
985      
986      //setExpectedOrder(order, actionOnRx);
987    } else {
988      //too much info blocks
989      order = 0;
990    }
991    return order;
992  }
993  
994  
995  
996  /**Adds the info block to send 'get value by path'
997   * @param sPathInTarget
998   * @return The order number. 0 if the cmd can't be created.
999   */
1000  public int cmdGetValueByPath(String sPathInTarget, InspcAccessExecRxOrder_ifc actionOnRx)
1001  { int order = 5;
1002    int lengthItem = InspcTelgInfoSet.lengthCmdGetValueByPath(sPathInTarget.length());
1003    if(prepareTelg(lengthItem)) {
1004      //InspcTelgInfoSet infoGetValue = new InspcTelgInfoSet();
1005      InspcTelgInfoSet infoAccess = newTxitem();
1006      txAccess.addChild(infoAccess);
1007      order = orderGenerator.getNewOrder();
1008      infoAccess.setCmdGetValueByPath(sPathInTarget, order);
1009      if(sPathInTarget.equals("_DSP_.ccs_1P.ccs_IB_priv.ictrl.pire_p.out.YD.")) {
1010        System.out.println("InspcTargetAccessor.cmdGetValueByPath - check, " +  sPathInTarget + ", " + infoAccess.toString());
1011        ///Debugutil.stop();
1012      }  
1013
1014      if(logTelg !=null){ 
1015        logTelg.sendMsg(identLogTelg+idLogGetValueByPath, "add cmdGetValueByPath %s, order = %d", sPathInTarget, new Integer(order)); 
1016      }
1017      if(sPathInTarget.contains("xWCP_1"))
1018        Debugutil.stop();
1019      setExpectedOrder(order, actionOnRx);
1020    } else {
1021      //too much info blocks
1022      order = 0;
1023    }
1024    return order;
1025  }
1026  
1027  
1028  
1029  /**Adds the info block to send 'register by path'
1030   * @param sPathInTarget
1031   * @return The order number. 0 if the cmd can't be created because the telegram is full.
1032   */
1033  public int cmdRegisterHandle(String sPathInTarget, InspcAccessExecRxOrder_ifc actionOnRx)
1034  { final int order;
1035    final int zPath = sPathInTarget.length();
1036    final int restChars = 4 - (zPath & 0x3);  //complete to a 4-aligned length
1037    prepareTelg(InspcDataExchangeAccess.Inspcitem.sizeofHead + zPath + restChars);
1038    order = orderGenerator.getNewOrder();
1039    setExpectedOrder(order, actionOnRx);
1040    InspcTelgInfoSet infoAccess = newTxitem();
1041    txAccess.addChild(infoAccess);  
1042    infoAccess.addChildString(sPathInTarget);
1043    if(restChars >0) { infoAccess.addChildInteger(restChars, 0); }
1044    final int zInfo = infoAccess.getLength();
1045    infoAccess.setInfoHead(zInfo, InspcDataExchangeAccess.Inspcitem.kRegisterHandle, order);
1046    //
1047    if(logTelg !=null){ 
1048      logTelg.sendMsg(identLogTelg+idLogRegisterByPath, "add registerByPath %s, order = %d", sPathInTarget, new Integer(order)); 
1049    }
1050    return order;
1051  }
1052  
1053  
1054  
1055  /**Adds the info block to send 'get value by ident'
1056   * @param sPathInTarget
1057   * @return The order number. 0 if the cmd can't be created because the telegram is full.
1058   */
1059  @Override public boolean cmdGetValueByHandle(int ident, InspcAccessExecRxOrder_ifc action)
1060  { if(ixIdent5GetValueByIdent >= actionRx4GetValueByHandle.length){
1061      return false;
1062      //  txCmdGetValueByIdent();
1063    }
1064    actionRx4GetValueByHandle[ixIdent5GetValueByIdent] = action;
1065    accInfoDataGetValueByIdent.addChildInteger(4, ident);
1066    ixIdent5GetValueByIdent +=1;
1067    return true;
1068  }
1069  
1070  
1071  /**
1072   * @return true if the telegram is sent.
1073   */
1074  boolean txCmdGetValueByIdent() {
1075    if(ixIdent5GetValueByIdent > 0 && isOrSetReady(System.currentTimeMillis())){
1076      int lengthInfo = accInfoDataGetValueByIdent.getLength();
1077      //It prepares the telg head.
1078      if(prepareTelg(lengthInfo)){  //It finishes an existing telegram if there is not enough space for the idents-info
1079        int order = 0xabcdef01; //not neccessary. //orderGenerator.getNewOrder();
1080        //setExpectedOrder(order, actionRx4ValueByIdent);
1081        InspcTelgInfoSet infoAccess = newTxitem();
1082        txAccess.addChild(infoAccess);
1083        int posInTelg = infoAccess.getPositionInBuffer() + InspcDataExchangeAccess.Inspcitem.sizeofHead;
1084        System.arraycopy(dataInfoDataGetValueByIdent, 0, infoAccess.getData(), posInTelg, 4 * ixIdent5GetValueByIdent);
1085        infoAccess.setInfoHead(lengthInfo + InspcDataExchangeAccess.Inspcitem.sizeofHead, InspcDataExchangeAccess.Inspcitem.kGetValueByHandle, order);
1086        ixIdent5GetValueByIdent = 0;
1087        accInfoDataGetValueByIdent.assignClear(dataInfoDataGetValueByIdent);
1088        return true;
1089      } else {
1090        return false; //any problem, tegegram can't be sent.
1091      }
1092    } else return false; //no data
1093  }
1094  
1095  
1096  
1097  
1098  final void execRx4ValueByHandle(InspcDataExchangeAccess.Inspcitem inspcitem, long time, LogMessage log, int identLog){
1099    //int lenInfo = info.getLength();
1100    InspcDataExchangeAccess.InspcAnswerValueByHandle answerItem = new InspcDataExchangeAccess.InspcAnswerValueByHandle(inspcitem);
1101    final int ixValStart = answerItem.getIxHandleFrom();  //first index of variable in this answer item
1102    final int ixValTo = answerItem.getIxHandleTo();  //first index of variable in this answer item
1103    int ixVal = ixValStart;  //the suggested index of the action, proper to tx
1104    while(ixVal < ixValTo){  //at least one byte in info, 
1105      InspcAccessExecRxOrder_ifc action = actionRx4GetValueByHandle[ixVal];
1106      ixVal +=1;
1107      if(action !=null){
1108        action.execInspcRxOrder(answerItem, time, log, identLog);
1109      }
1110    }
1111    //System.out.println("execRx4ValueByIdent");
1112    stop();
1113  }
1114  
1115
1116  
1117  /**Adds the info block to send 'get value by path'
1118   * @param sPathInTarget
1119   * @param value The value as long-image, it may be a double, float, int etc.
1120   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1121   *                    + {@link ClassJc#REFLECTION_double} etc.
1122   * @return The order number. 0 if the cmd can't be created.
1123   */
1124  @Override public void cmdSetValueByPath(String sPathInTarget, long value, int typeofValue, InspcAccessExecRxOrder_ifc actionOnRx)
1125  { int order;
1126    int zPath = sPathInTarget.length();
1127    int restChars = 4 - (zPath & 0x3);  //complete to a 4-aligned length
1128    int zInfo = InspcDataExchangeAccess.Inspcitem.sizeofHead + InspcDataExchangeAccess.InspcSetValue.sizeofElement + zPath + restChars; 
1129    if(prepareTelg(zInfo )){
1130      InspcTelgInfoSet infoAccess = newTxitem();
1131      txAccess.addChild(infoAccess);
1132      order = orderGenerator.getNewOrder();
1133      //infoAccess.setCmdSetValueByPath(sPathInTarget, value, typeofValue, order);
1134      InspcDataExchangeAccess.InspcSetValue accessSetValue = new InspcDataExchangeAccess.InspcSetValue(); 
1135      infoAccess.addChild(accessSetValue);
1136      accessSetValue.setLong(value);
1137      infoAccess.addChildString(sPathInTarget);
1138      if(restChars >0) { infoAccess.addChildInteger(restChars, 0); }
1139      assert(infoAccess.getLength() == zInfo);  //check length after add children. 
1140      infoAccess.setInfoHead(zInfo, InspcDataExchangeAccess.Inspcitem.kSetValueByPath, order);
1141      setExpectedOrder(order, actionOnRx);
1142      if(logTelg !=null){ 
1143        logTelg.sendMsg(identLogTelg+idLogSetValueByPath, "add cmdSetValueByPath %s, order = %d, value=%08X, type=%d", sPathInTarget, new Integer(order), new Long(value), new Integer(typeofValue)); 
1144      }
1145    } else {
1146      //too much info blocks
1147      order = 0;
1148    }
1149  }
1150  
1151  
1152  /**Sends the given telegram if the requested command doesn't fit in the telegram yet,
1153   * prepares the given command as info in the given or a new one telegram and registers the exec on answer.
1154   * <br><br>
1155   * After the last such request {@link #sendAndAwaitAnswer()} have to be called
1156   * to send at least the last request. 
1157   * @param sPathInTarget
1158   * @param value The value as long-image, it may be a double, float, int etc.
1159   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1160   *                    + {@link ClassJc#REFLECTION_double} etc.
1161   * @param exec The routine to execute on answer.
1162   * @return true if a new telegram was created. It is an info only.
1163   * 
1164   */
1165  @Deprecated
1166  public boolean sendAndPrepareCmdSetValueByPath(String sPathInTarget, long value, int typeofValue, InspcAccessExecRxOrder_ifc exec)
1167  { int order;
1168    boolean sent = false;
1169    do {
1170      order = 0; cmdSetValueByPath(sPathInTarget, value, typeofValue, exec);    
1171      if(order !=0){ //save the order to the action. It is taken on receive.
1172        this.setExpectedOrder(order, exec);
1173      } else {
1174        //XXXsendAndAwaitAnswer();  //calls execInspcRxOrder as callback.
1175        sent = true;
1176      }
1177    } while(order == 0);  
1178    return sent;
1179  }
1180  
1181  
1182  @Override public void cmdSetValueByPath(VariableAccessArray_ifc var, String value){
1183    assert(var instanceof InspcVariable);
1184    InspcVariable var1 = (InspcVariable)var;
1185    String valueTrimmed = value.trim();
1186    assert(var1.ds.targetAccessor == this);
1187    try{
1188        switch(var.getType()){
1189          case 'D':
1190          case 'F': {
1191            double val = Double.parseDouble(valueTrimmed); 
1192            cmdSetValueByPath(var1.ds.sPathInTarget, val, null); 
1193          } break;
1194          case 'S':
1195          case 'B':
1196          case 'I': {
1197            int val;
1198            if(valueTrimmed.startsWith("0x")){
1199              val = Integer.parseInt(valueTrimmed.substring(2),16); 
1200            } else {
1201              val = Integer.parseInt(valueTrimmed); 
1202            }
1203            cmdSetValueByPath(var1.ds.sPathInTarget, val, null); 
1204          } break;
1205          case 's': {  //empty yet
1206            
1207          } break;
1208        }
1209      } catch(Exception exc){
1210        //usual number format exception
1211        System.err.println("InspcTargetAccessor.cmdSetValueByPath - exception" + exc.getMessage() + "; ");
1212      }
1213 
1214  }
1215  
1216
1217  
1218  
1219  /**Adds the info block to send 'set value by path'
1220   * @param sPathInTarget
1221   * @param value The value as long-image, it may be a double, float, int etc.
1222   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1223   *                    + {@link ClassJc#REFLECTION_double} etc.
1224   * @return The order number. 0 if the cmd can't be created because the telgram is full.
1225   */
1226  public int cmdSetValueByPath(String sPathInTarget, int value)
1227  { int order;
1228    int lengthItem = InspcTelgInfoSet.lengthCmdSetValueByPath(sPathInTarget.length());
1229    if(prepareTelg(lengthItem)) {
1230      InspcTelgInfoSet infoAccess = newTxitem();
1231      txAccess.addChild(infoAccess);
1232      order = orderGenerator.getNewOrder();
1233      infoAccess.setCmdSetValueByPath(sPathInTarget, value, order);
1234    } else {
1235      //too much info blocks
1236      order = 0;
1237    }
1238    return order;
1239  }
1240  
1241  
1242  /**Adds the info block to send 'set value by path'
1243   * @param sPathInTarget
1244   * @param value The value as int value, 32 bit
1245   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1246   *                    + {@link ClassJc#REFLECTION_double} etc.
1247   * @return The order number. 0 if the cmd can't be created because the telgram is full.
1248   */
1249  public void cmdSetValueByPath(String sPathInTarget, int value, InspcAccessExecRxOrder_ifc actionOnRx)
1250  { int order;
1251    int lengthItem = InspcTelgInfoSet.lengthCmdSetValueByPath(sPathInTarget.length());
1252    if(prepareTelg(lengthItem)) {
1253      InspcTelgInfoSet infoAccess = newTxitem();
1254      txAccess.addChild(infoAccess);
1255      order = orderGenerator.getNewOrder();
1256      infoAccess.setCmdSetValueByPath(sPathInTarget, value, order);
1257      setExpectedOrder(order, actionOnRx);
1258      if(logTelg !=null){ 
1259        logTelg.sendMsg(identLogTelg+idLogSetValueByPath, "add cmdSetValueByPath %s, order = %d, value=%d", sPathInTarget, new Integer(order), new Integer(value)); 
1260      }
1261    }   
1262  }
1263  
1264  
1265  /**Adds the info block to send 'set value by path'
1266   * @param sPathInTarget
1267   * @param value The value as long-image, it may be a double, float, int etc.
1268   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1269   *                    + {@link ClassJc#REFLECTION_double} etc.
1270   * @return The order number. 0 if the cmd can't be created because the telgram is full.
1271   */
1272  public void cmdSetValueByPath(String sPathInTarget, float value, InspcAccessExecRxOrder_ifc actionOnRx)
1273  { int order;
1274    int lengthItem = InspcTelgInfoSet.lengthCmdSetValueByPath(sPathInTarget.length());
1275    if(prepareTelg(lengthItem)) {
1276      InspcTelgInfoSet infoAccess = newTxitem();
1277      txAccess.addChild(infoAccess);
1278      order = orderGenerator.getNewOrder();
1279      infoAccess.setCmdSetValueByPath(sPathInTarget, value, order);
1280      setExpectedOrder(order, actionOnRx);
1281      if(logTelg !=null){ 
1282        logTelg.sendMsg(identLogTelg+idLogSetValueByPath, "add cmdSetValueByPath %s, order = %d, value=%f", sPathInTarget, new Integer(order), new Float(value)); 
1283      }
1284    }   
1285  }
1286  
1287  
1288  /**Adds the info block to send 'set value by path'
1289   * @param sPathInTarget
1290   * @param value The value as long-image, it may be a double, float, int etc.
1291   * @param typeofValue The type of the value, use {@link InspcDataExchangeAccess#kScalarTypes}
1292   *                    + {@link ClassJc#REFLECTION_double} etc.
1293   * @return The order number. 0 if the cmd can't be created.
1294   */
1295  public void cmdSetValueByPath(String sPathInTarget, double value, InspcAccessExecRxOrder_ifc actionOnRx)
1296  { int order;
1297    int lengthItem = InspcTelgInfoSet.lengthCmdSetValueByPath(sPathInTarget.length());
1298    if(prepareTelg(lengthItem)) {
1299      InspcTelgInfoSet infoAccess = newTxitem();
1300      txAccess.addChild(infoAccess);
1301      order = orderGenerator.getNewOrder();
1302      infoAccess.setCmdSetValueByPath(sPathInTarget, value, order);
1303      setExpectedOrder(order, actionOnRx);
1304      if(logTelg !=null){ 
1305        logTelg.sendMsg(identLogTelg+idLogSetValueByPath, "add cmdSetValueByPath %s, order = %d, value=%f", sPathInTarget, new Integer(order), new Double(value)); 
1306      }
1307    }
1308  }
1309  
1310  
1311  /**Adds the info block to send 'get address by path'
1312   * @param sPathInTarget
1313   * @return The order number. 0 if the cmd can't be created.
1314   * @since 2014-04-28 new form
1315   */
1316  @Override public boolean cmdGetAddressByPath(String sPathInTarget, InspcAccessExecRxOrder_ifc actionOnRx)
1317  { int order;
1318    int lengthItem = InspcTelgInfoSet.lengthCmdGetAddressByPath(sPathInTarget.length());
1319    if(prepareTelg(lengthItem)) {
1320      //InspcTelgInfoSet infoGetValue = new InspcTelgInfoSet();
1321      InspcTelgInfoSet infoAccess = newTxitem();
1322      txAccess.addChild(infoAccess);
1323      order = orderGenerator.getNewOrder();
1324      infoAccess.setCmdGetAddressByPath(sPathInTarget, order);
1325      setExpectedOrder(order, actionOnRx);
1326      if(logTelg !=null){ 
1327        logTelg.sendMsg(identLogTelg + idLogGetAddress, "add cmdGetAddressByPath %s, order = %d", sPathInTarget, new Integer(order)); 
1328      }
1329    } else {
1330      //too much telegrams
1331      throw new IllegalArgumentException("InspcTargetAccessor - too much telegrams;");
1332    }
1333    return true;
1334  }
1335  
1336  
1337  
1338  /**This routine have to be called after the last cmd in one thread. It sends the last telg
1339   * or initialized the send for previous telgs if the answer is not gotten yet.
1340   * @return true if anything to send, false if no cmd was given.
1341   */
1342  public boolean cmdFinit(){
1343    states.processEvent(evSend);
1344    if(!bTaskPending.get()) {
1345      txCmdGetValueByIdent();
1346      if(bFillTelg || _tdata.txixFill >0){
1347        if(bFillTelg) {
1348          completeDatagram(true);
1349        }
1350        bTaskPending.set(true);
1351        send();   //send the first telegramm now
1352        return true;
1353      }
1354      else return false;
1355    } 
1356    else return false;  //nothing to do
1357  }
1358  
1359  
1360  public void setStateToUser(InspcPlugUser_ifc user) {
1361    if(user !=null){
1362      InspcPlugUser_ifc.TargetState stateUser;
1363      if(bTaskPending.get()){ stateUser = InspcPlugUser_ifc.TargetState.waitReceive; }
1364      else { stateUser = InspcPlugUser_ifc.TargetState.idle; }
1365      user.showStateInfo(name, stateUser, _tdata.nSeqNumber, cycle_timeout);
1366    }
1367  }
1368  
1369  /**Returns whether a tx telegram is filled with any info blocks.
1370   * The user can check it. The user needn't store itself whether any call of cmd...() is done.
1371   * It helps in management info blocks.
1372   * @return true if any call of cmd...() was done and the send() was not called.
1373   */
1374  public boolean isFilledTxTelg(){ return bFillTelg; }
1375  
1376  /**Returns true if any cmd..() call doesn't fit in the current telegram, therefore the tx telegram
1377   * should be send firstly.
1378   */
1379  public boolean shouldSend(){ return bShouldSend; }
1380  
1381  
1382  
1383  /**Completes this datagram with all head information.
1384   */
1385  private void completeDatagram(boolean lastTelg){
1386    assert(bFillTelg);
1387    int lengthDatagram = txAccess.getLength();
1388    if(_tdata.txixFill < _tdata.tx.length) {
1389      assert(lengthDatagram <= _tdata.tx[_tdata.txixFill].buffer.length);
1390      _tdata.tx[_tdata.txixFill].nrofBytesTelg = lengthDatagram;
1391      txAccess.setLengthDatagram(lengthDatagram);
1392      _tdata.tx[_tdata.txixFill].nSeq = _tdata.nSeqNumber;
1393      _tdata.tx[_tdata.txixFill].lastTelg = lastTelg;
1394      bFillTelg = false;
1395      state = 's';
1396      if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - complete Datagram; " + lastTelg + "; " + _tdata.txixFill + "; seqnr " + _tdata.nSeqNumber);
1397      _tdata.txixFill +=1;
1398    }
1399  }
1400  
1401  
1402  
1403  
1404        /**Sends the prepared telegram.
1405         * @return
1406         */
1407  private void send()
1408  {
1409    //send the telegram:
1410    //checkerRxTelg.setAwait(nSeqNumber);  
1411    if(name.equals(dbgNameStopTx)) {
1412      Debugutil.stop();
1413    }
1414    timeSend = System.currentTimeMillis();
1415    _tdata.nSeqNumberTxRx = _tdata.tx[_tdata.txixSend].nSeq;
1416    //bSendPending = true;
1417    bIsSentTelg = true;
1418    int lengthDatagram = _tdata.tx[_tdata.txixSend].nrofBytesTelg;
1419    //tx[ixTxSend].nrofBytesTelg = -1; //is sent
1420    if(lengthDatagram >0) {
1421      int ok = commPort.send(this, _tdata.tx[_tdata.txixSend].buffer, lengthDatagram);
1422      synchronized(this){
1423        if(ok == 96)
1424          Debugutil.stop();
1425      }
1426      if(logTelg !=null){ 
1427        logTelg.sendMsg(identLogTelg +idLogTx, "send telg ix=%d, length= %d, ok = %d, seqn=%d", new Integer(_tdata.txixSend), new Integer(lengthDatagram)
1428        , new Integer(ok), new Integer(_tdata.nSeqNumberTxRx)); 
1429      }
1430    } else {
1431      Debugutil.stop();
1432      System.out.println("InspcTargetAccessor.send() - target does not response, too many telegr, " + targetAddr);
1433    }
1434    bShouldSend = false; 
1435  }
1436        
1437        
1438        
1439  /**This routine is called from the received thread if a telegram with the sender of this target
1440   * was received.
1441   * <br><br>
1442   * A communication cycle consists of maybe more as one answer for one request telegram
1443   * and maybe more as one request telegram. This routine checks whether all answers for the pending
1444   * request telegram were received. Only if all telegrams where received (especially the last one)
1445   * then the maybe next request telegram is sent.
1446   * <br><br>
1447   * If all telegrams of the communication cycle are received, the flag {@link #bTaskPending} is set to false 
1448   * and the {@link #isReady(long)} method will return true.
1449   * <br><br>
1450   * If any answer is missed, especially because the communication is disturbed or the device is faulty,
1451   * then the {@link #isReady(long)} returns false till the given timeout has expired.
1452   * @param rxBuffer
1453   * @param rxLength
1454   */
1455  public void evaluateRxTelg(byte[] rxBuffer, int rxLength){
1456    bRunInRxThread = true;
1457    try{ 
1458      timeReceive = System.currentTimeMillis();
1459      dtimeReceive = timeReceive - timeSend;       
1460      if(logTelg !=null){ 
1461        logTelg.sendMsg(identLogTelg+idLogRx, "recv telg after %d ms", new Long(dtimeReceive)); 
1462      }
1463      long time = System.currentTimeMillis();
1464      final InspcDataExchangeAccess.InspcDatagram accessRxTelg = new InspcDataExchangeAccess.InspcDatagram();
1465      accessRxTelg.assign(rxBuffer, rxLength);
1466      int rxSeqnr = accessRxTelg.getSeqnr();
1467      //int rxAnswerNr = accessRxTelg.getAnswerNr();
1468      if(rxSeqnr == this._tdata.nSeqNumberTxRx){
1469        //the correct answer
1470        int nAnswer = accessRxTelg.getAnswerNr() - 1;  
1471        if(nAnswer == -1) { //has sent 0, old Target
1472          nAnswer = 0;
1473          _tdata.oldTarget = true;  //target has sent 0, old target, store for ever.
1474        } else if(_tdata.oldTarget) {
1475          nAnswer = (nAnswer +1) >>1;  //add 1 because it starts with 0, shift because 2. telegram has 2 etc.
1476        }
1477        int bitAnswer = 1 << (nAnswer & 0x3f);
1478        if((_tdata.rxBitsAnswerNr & bitAnswer) ==0) { //this answer is not processed yet?
1479          //a new answer, not processed
1480          _tdata.rxBitsAnswerNr |= bitAnswer;
1481          //
1482          _tdata.rxDatagram[nAnswer] = accessRxTelg;  //store the telegram to evaluate in the inspector thread. 
1483          //
1484          if(accessRxTelg.lastAnswer()) {
1485            _tdata.rxNrofDatagramsForOneSend = nAnswer +1;  //signal for evaluating in InspcMng-thread
1486            _tdata.rxBitsAnswerMask = (1 << _tdata.rxNrofDatagramsForOneSend) -1;  //for all this bits an anwer should be received.
1487            if(_tdata.rxBitsAnswerMask != _tdata.rxBitsAnswerNr) {
1488              Debugutil.stop();  //last telegram received before antecedent ones.
1489            }
1490            //All received telegrams for this send telegram will be evaluated together if bitsAnswerMask == bitsAnswerNrRx
1491            //ttt states.processEvent(evLastAnswer);
1492            if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - Rcv last answer; " + rxSeqnr);
1493            if(logTelg !=null){ 
1494              logTelg.sendMsg(identLogTelg+idLogRxLast, "recv ok last telg seqn=%d nAnswer=%d after %d ms", new Integer(rxSeqnr), new Integer(nAnswer), new Long(dtimeReceive)); 
1495            }
1496            /*ttt
1497            if((debugRxTelgIx +=1) > debugRxTelg.length){
1498              debugRxTelgIx = debugRxTelg.length -1;   //prevent exception for too many telegs.
1499              System.err.println("InspcTargetAccessor - too many telg seq");
1500            }
1501            // 
1502            txNextAfterRcvOrSetReady();  //see isReady
1503            */
1504            //
1505          } else {
1506            //sendPending: It is not the last answer, remain true
1507            if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - Rcv answer; " + nAnswer + "; seqn=" + rxSeqnr);
1508            if(logTelg !=null){ 
1509              logTelg.sendMsg(identLogTelg+idLogRx, "recv ok not last telg seqn=%d nAnswer=%d after %d ms", new Integer(rxSeqnr), new Integer(nAnswer), new Long(dtimeReceive)); 
1510            }
1511          }
1512        } else {
1513          //duplicate answer for this sequence:
1514          if(logTelg !=null || bWriteDebugSystemOut) System.out.println("InspcTargetAccessor - faulty answer in sequence, received= " + nAnswer + ", expected=0x" + Long.toHexString(_tdata.rxBitsAnswerNr));
1515          //faulty seqnr
1516          if(logTelg !=null){ 
1517            logTelg.sendMsg(identLogTelg+idLogRxRepeat, "recv repeated telg seqn=%d nAnswer=%d after %d ms", new Integer(rxSeqnr), new Integer(nAnswer), new Long(dtimeReceive)); 
1518          }
1519        }
1520      } else {
1521        //faulty seqnr ?sendPending: is false, unexpected rx
1522        if(logTelg !=null || bWriteDebugSystemOut) System.out.println("InspcTargetAccessor - unexpected seqnr, received=" + rxSeqnr + ", expected=" + _tdata.nSeqNumberTxRx);
1523        if(logTelg !=null){ 
1524          logTelg.sendMsg(identLogTelg+idLogFailedSeq, "recv failed seqn=%d after %d ms", new Integer(rxSeqnr), new Long(dtimeReceive)); 
1525        }
1526  
1527      }
1528    } finally {
1529      bRunInRxThread = false;
1530    }
1531  }
1532  
1533  
1534  
1535  /**This routine is invoked cyclically in the inspector thread. It checks whether telegrams are received.
1536   * 
1537   */
1538  public void evaluateRxTelgInspcThread(){
1539    long time = System.currentTimeMillis();
1540    if(_tdata.rxBitsAnswerNr >0 && _tdata.rxBitsAnswerNr == _tdata.rxBitsAnswerMask) { //only somewhat to do if received telegrams exists.
1541      //all telegrams from one send telegram are received. Usual it is only one telegram.
1542      try { 
1543        for(int ixRx = 0; ixRx < _tdata.rxNrofDatagramsForOneSend; ++ixRx) {
1544          DebugTxRx dbgRx = _tdata.bDebugTelg ? _tdata.debugTxRx [_tdata.txixSend] : null;
1545          evaluateOneDatagram(_tdata.rxDatagram[ixRx], null, time, logTelg, identLogTelg +idLogRxItem, dbgRx, ixRx);  ////
1546          //evaluateRx1TelgInspcThread(rxDatagram[ixRx]);
1547        }
1548      } catch(Exception exc) {
1549        CharSequence text = Assert.exceptionInfo("InspcTargetAccessor - Exception while evaluating ", exc, 0, 20);
1550        System.err.append(text);
1551      }
1552      states.processEvent(evLastAnswer);
1553      // 
1554      //
1555      //after evaluating the answer, send a next telegram for this communication cycle:
1556      //check whether it is the last telegram:
1557      //
1558      //boolean wasLastTxTelg = tlg.tx[tlg.ixTxSend].lastTelg;  //the ixTxSend is the index of send still.
1559      for(int ixRx = 0; ixRx < _tdata.rxNrofDatagramsForOneSend; ++ixRx) {
1560        _tdata.rxDatagram [ixRx] = null;  //garbage it.
1561      }
1562      //debugData ... not cleared here, cleared for txData lastly.
1563      _tdata.rxNrofDatagramsForOneSend = 0;
1564      _tdata.rxBitsAnswerNr = _tdata.rxBitsAnswerMask = 0;
1565      if(++_tdata.txixSend < _tdata.txixFill){
1566        if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - Send next telg; seqnr=" + _tdata.tx[_tdata.txixSend].nSeq + "; ixTxSend= " + _tdata.txixSend);
1567        //Note: sendPending remain set. For this next telegram.
1568        send();
1569      } else { //if(wasLastTxTelg){  //last is reached.
1570        lastTelg();  //action after receiving the last telegram from the last send telegram.
1571                     //invoke callbacksOnAnswer if stored. 
1572        setReady();    
1573        //Now new send telegrams can be prepared. Firstly it would check whether there are 
1574        bRequestWhileTaskPending = false;
1575        if(logTelg !=null && bWriteDebugSystemOut) System.out.println("InspcTargetAccessor.Test - All received; ");
1576      }  
1577    }
1578  }
1579
1580  
1581  /**This routine checks whether the communication is in its tx request gathering state: {@link #isOrSetReady(long)}
1582   * returns true. Then given {@link #addUserTxOrder(Runnable)} are invoked, which fills the tx telegram usual.
1583   * This routine is only invoked in the {@link org.vishia.inspcPV.mng.InspcMng#procComm()} routine cyclically for any target.
1584   * It is not intent to invoke by an application.
1585   * 
1586   */
1587  public void checkExecuteSendUserOrder(){
1588    if(isOrSetReady(System.currentTimeMillis())) {
1589      Runnable userTxOrder;
1590      if(getFieldsData.requFields !=null){
1591        System.out.println("InspcTargetAccessor - send getFields;");
1592        String path = this.getFieldsData.requFields.sPathInTarget; //getTargetFromPath(this.requestedFields.path()); 
1593        //InspcTargetAccessor targetAccessor = requestedFields.targetAccessor();
1594        callbacksOnAnswer.put(new Integer(getFieldsData.runOnResponseFields.hashCode()), getFieldsData.runOnResponseFields);  //register the same action only one time.
1595        cmdGetFields(path, this.getFieldsData.rxActionGetFields);
1596        getFieldsData.bGetFieldsPending = true;  //prevents request some more, isOrSetReady returns false after them.
1597        this.getFieldsData.requFields = null;
1598      }
1599      //
1600      while( (userTxOrder = userTxOrders.poll()) !=null){
1601        userTxOrder.run(); //maybe add some more requests to the current telegram.
1602      }
1603    }    
1604  }
1605  
1606  
1607  
1608  
1609  
1610  
1611        /**Waits for answer from the target.
1612         * This method can be called in any users thread. Typically it is the thread, which has send the telegram
1613         * to the target. 
1614         * 
1615         * @param timeout for waiting.
1616         * @return null on timeout, the answer datagrams elsewhere.
1617         * @since 2014-04-28 commented as deprecated
1618         * @deprecated The communication handles several requests. It is not proper that one await is programmed.
1619         *   The answer will be gotten for any information unit in the telegrams. 
1620         *   See {@link InspcAccessExecRxOrder_ifc}-argument of any {@link #cmdGetValueByPath(String, InspcAccessExecRxOrder_ifc)}...
1621         *   routine.
1622         */
1623        @Deprecated
1624  public InspcDataExchangeAccess.InspcDatagram[] awaitAnswer(int timeout)
1625        { //InspcDataExchangeAccess.ReflDatagram[] answerTelgs = checkerRxTelg.waitForAnswer(timeout); 
1626        long time = System.currentTimeMillis();
1627    dtimeWeakup = time - timeSend;
1628    return null; //answerTelgs;
1629  }
1630        
1631        
1632        
1633        
1634  
1635  /**Clean up the order list.
1636   * @param timeOld The time before that the orders are old. 
1637   * @return positive: number of removed orders. negative: number of found orders, whereby nothing is removed. 
1638   *   Usual 0 if no orders are pending. If >0, some orders are wrong, if <0, the communication is slow.
1639   */
1640  public int checkAndRemoveOldOrders(long timeOld)
1641  {
1642    int foundOrders = 0;
1643    int removedOrders = 0;
1644    boolean bRepeatBecauseModification;
1645    do{
1646      bRepeatBecauseModification = false;
1647      //if(ordersExpected.size() > 10){
1648        Set<Map.Entry<Integer, OrderWithTime>> list = ordersExpected.entrySet();
1649        try{
1650          Iterator<Map.Entry<Integer, OrderWithTime>> iter = list.iterator();
1651          while(iter.hasNext()){
1652            foundOrders +=1;
1653            Map.Entry<Integer, OrderWithTime> entry = iter.next();
1654            OrderWithTime timedOrder = entry.getValue();
1655            if(timedOrder.time < timeOld){
1656              iter.remove();
1657              removedOrders +=1;
1658            }
1659          }
1660        } catch(Exception exc){ //Repeat it, the list ist modified
1661          bRepeatBecauseModification = true;
1662        }
1663      //}
1664    } while(bRepeatBecauseModification);
1665      
1666    return removedOrders > 0 ? removedOrders : -foundOrders;
1667  }
1668  
1669  
1670  
1671  /**Evaluates a received telegram.
1672   * @param telgHead The telegram
1673   * @param executer if given, than the {@link InspcAccessExecRxOrder_ifc#execInspcRxOrder(org.vishia.communication.InspcDataExchangeAccess.Inspcitem)}
1674   *        -method is called for any info block.<br>
1675   *        If null, then the order is searched like given with {@link #setExpectedOrder(int, InspcAccessExecRxOrder_ifc)}
1676   *        and that special routine is executed.
1677   * @return null if no error, if not null then it is an error description. 
1678   * @since 2015-08 it does not return an error but it writes to System.err on failure. It continues if possible thow an item may be faulty.
1679   */
1680  public void evaluateOneDatagram(InspcDataExchangeAccess.InspcDatagram telgHead
1681      , InspcAccessExecRxOrder_ifc executer, long time, LogMessage log, int identLog, DebugTxRx dbgRx, int dbgixAnswer)
1682  { String sError = null;
1683    //int currentPos = InspcDataExchangeAccess.InspcDatagram.sizeofHead;
1684    //for(InspcDataExchangeAccess.ReflDatagram telgHead: telgHeads){
1685    int nrofBytesDatagramReceived = telgHead.getLengthTotal();
1686    int nrofBytesDatagramInHead = telgHead.getLengthDatagram();
1687    if(dbgRx !=null) {
1688      dbgRx.nrofBytesDatagramInHead = nrofBytesDatagramInHead;          
1689      dbgRx.nrofBytesDatagramReceived = nrofBytesDatagramReceived;
1690      assert(dbgRx.nrofBytesDatagramInHead == dbgRx.nrofBytesDatagramReceived); 
1691      dbgRx.rxTelgHead[dbgixAnswer] = telgHead;
1692    }
1693    if(dbgRx.nrofBytesDatagramInHead != dbgRx.nrofBytesDatagramReceived) {
1694      System.err.println("ERROR InscTargetAccessor.evaluateOneDatagram - mismatch between nrofBytesDatagramReceived, nrofBytesDatagramInHead, " + nrofBytesDatagramReceived+ " != " + nrofBytesDatagramInHead);
1695      return;
1696    }
1697    //int nrofBytesTelg = telgHead.getLength();  //length from ByteDataAccess-management.
1698    //telgHead.assertNotExpandable();
1699    while(sError == null && telgHead.sufficingBytesForNextChild(InspcDataExchangeAccess.Inspcitem.sizeofHead)){
1700      ////
1701      final InspcDataExchangeAccess.Inspcitem infoAccessRx;
1702      if(dbgRx ==null) {
1703        _tdata.accRxItemStatic.detach();
1704        infoAccessRx = _tdata.accRxItemStatic;
1705      } else {
1706        infoAccessRx = new InspcDataExchangeAccess.Inspcitem();
1707        dbgRx.rxItems[dbgixAnswer].add(infoAccessRx); 
1708      }
1709      telgHead.addChild(infoAccessRx);
1710      int nrofBytesInfo = infoAccessRx.getLenInfo();
1711      int posInData = infoAccessRx.getPositionInBuffer();
1712      if(!infoAccessRx.checkLengthElement(nrofBytesInfo)) {
1713        System.err.println("ERROR InscTargetAccessor.evaluateOneDatagram - mismatch between nrofBytesInfo, nrofBytesDatagramInHead, " + nrofBytesDatagramReceived+ " != " + nrofBytesDatagramInHead);
1714        return;
1715      }
1716      if((posInData + nrofBytesInfo) > nrofBytesDatagramInHead) {
1717        System.err.println("ERROR InscTargetAccessor.evaluateOneDatagram - mismatch between nrofBytesInfo, nrofBytesDatagramInHead, " + nrofBytesDatagramReceived+ " != " + nrofBytesDatagramInHead);
1718        return;
1719      }
1720      infoAccessRx.setLengthElement(nrofBytesInfo);  //if an exception throws or evaluation of infoAccess is aborted, is known length.
1721      if(executer !=null){
1722        //deprecated and unused.
1723        executer.execInspcRxOrder(infoAccessRx, time, log, identLog);
1724      } else {
1725        //that is correct:
1726        int cmd = infoAccessRx.getCmd();
1727        if(cmd == InspcDataExchangeAccess.Inspcitem.kAnswerFieldMethod){
1728          //special case: The same order number is used for more items in the same sequence number.
1729          //callback the proper request for get fileds to any InspcVariable.
1730          getFieldsData.orderGetFields.exec.execInspcRxOrder(infoAccessRx, time, log, identLog);
1731        }
1732        else if(cmd == InspcDataExchangeAccess.Inspcitem.kAnswerValueByHandle){
1733          ////
1734          execRx4ValueByHandle(infoAccessRx, time, log, identLog);
1735        }
1736        else {
1737          //
1738          int order = infoAccessRx.getOrder();
1739          OrderWithTime timedOrder = ordersExpected.remove(order);
1740          if(timedOrder !=null){
1741            //remove timed order
1742            InspcAccessExecRxOrder_ifc orderExec = timedOrder.exec;
1743            if(orderExec !=null){
1744              orderExec.execInspcRxOrder(infoAccessRx, time, log, identLog);
1745            } else {
1746              stop();  //should not 
1747            }
1748          }
1749        }
1750        //
1751        //search the order whether it is expected:
1752      }
1753      infoAccessRx.setLengthElement(nrofBytesInfo);
1754      //telgHead.setLengthCurrentChildElement(nrofBytesInfo); //to add the next.
1755      //currentPos += nrofBytesInfo;  //the same as stored in telgHead-access
1756      
1757    }
1758    //return sError;
1759  }
1760  
1761  
1762  
1763  public static float valueFloatFromRxValue(InspcDataExchangeAccess.Inspcitem info, int type)
1764  {
1765    float ret = 0;
1766    if(type >= InspcDataExchangeAccess.kScalarTypes){
1767      switch(type - InspcDataExchangeAccess.kScalarTypes){
1768        case org.vishia.reflect.ClassJc.REFLECTION_char16: ret = (char)info.getChildInteger(2); break;
1769        case org.vishia.reflect.ClassJc.REFLECTION_char8: ret = (char)info.getChildInteger(1); break;
1770        case org.vishia.reflect.ClassJc.REFLECTION_double: ret = (float)info.getChildDouble(); break;
1771        case org.vishia.reflect.ClassJc.REFLECTION_float: ret = info.getChildFloat(); break;
1772        case org.vishia.reflect.ClassJc.REFLECTION_int8: ret = info.getChildInteger(-1); break;
1773        case org.vishia.reflect.ClassJc.REFLECTION_int16: ret = info.getChildInteger(-2); break;
1774        case org.vishia.reflect.ClassJc.REFLECTION_int32: ret = info.getChildInteger(-4); break;
1775        case org.vishia.reflect.ClassJc.REFLECTION_int64: ret = info.getChildInteger(-8); break;
1776        case org.vishia.reflect.ClassJc.REFLECTION_int: ret = info.getChildInteger(-4); break;
1777        case org.vishia.reflect.ClassJc.REFLECTION_uint8: ret = info.getChildInteger(1); break;
1778        case org.vishia.reflect.ClassJc.REFLECTION_uint16: ret = info.getChildInteger(2); break;
1779        case org.vishia.reflect.ClassJc.REFLECTION_uint32: ret = info.getChildInteger(4); break;
1780        case org.vishia.reflect.ClassJc.REFLECTION_uint64: ret = info.getChildInteger(8); break;
1781        case org.vishia.reflect.ClassJc.REFLECTION_uint: ret = info.getChildInteger(4); break;
1782        case org.vishia.reflect.ClassJc.REFLECTION_boolean: ret = info.getChildInteger(1) == 0 ? 0.0f: 1.0f; break;
1783      }      
1784    } else if(type <= InspcDataExchangeAccess.maxNrOfChars){
1785      try{
1786        String sValue = info.getChildString(type);
1787        ret = Float.parseFloat(sValue);
1788      } catch(Exception exc){ ret = 0; }
1789    }
1790
1791    return ret;
1792  }
1793  
1794  
1795  
1796  
1797
1798  public static int valueIntFromRxValue(InspcDataExchangeAccess.Inspcitem info, int type)
1799  {
1800    int ret = 0;
1801    if(type >= InspcDataExchangeAccess.kScalarTypes){
1802      switch(type - InspcDataExchangeAccess.kScalarTypes){
1803        case ClassJc.REFLECTION_char16: ret = (char)info.getChildInteger(2); break;
1804        case org.vishia.reflect.ClassJc.REFLECTION_char8:  ret = (char)info.getChildInteger(1); break;
1805        case org.vishia.reflect.ClassJc.REFLECTION_double: ret = (int)info.getChildDouble(); break;
1806        case org.vishia.reflect.ClassJc.REFLECTION_float:  ret = (int)info.getChildFloat(); break;
1807        case org.vishia.reflect.ClassJc.REFLECTION_int8:   ret = (int)info.getChildInteger(-1); break;
1808        case org.vishia.reflect.ClassJc.REFLECTION_int16:  ret = (int)info.getChildInteger(-2); break;
1809        case org.vishia.reflect.ClassJc.REFLECTION_int32:  ret = (int)info.getChildInteger(-4); break;
1810        case org.vishia.reflect.ClassJc.REFLECTION_int64:  ret = (int)info.getChildInteger(-8); break;
1811        case org.vishia.reflect.ClassJc.REFLECTION_int:    ret = (int)info.getChildInteger(-4); break;
1812        case org.vishia.reflect.ClassJc.REFLECTION_uint8:  ret = (int)info.getChildInteger(1); break;
1813        case org.vishia.reflect.ClassJc.REFLECTION_uint16: ret = (int)info.getChildInteger(2); break;
1814        case org.vishia.reflect.ClassJc.REFLECTION_uint32: ret = (int)info.getChildInteger(4); break;
1815        case org.vishia.reflect.ClassJc.REFLECTION_uint64: ret = (int)info.getChildInteger(8); break;
1816        case org.vishia.reflect.ClassJc.REFLECTION_uint:   ret = (int)info.getChildInteger(4); break;
1817        case org.vishia.reflect.ClassJc.REFLECTION_boolean:ret = info.getChildInteger(1) == 0 ? 0: 1; break;
1818      }      
1819    } else if(type == InspcDataExchangeAccess.kReferenceAddr){
1820      ret = (int)info.getChildInteger(4);
1821    } else if(type <= InspcDataExchangeAccess.maxNrOfChars){
1822      try{
1823        String sValue = info.getChildString(type);
1824        ret = Integer.parseInt(sValue);
1825      } catch(Exception exc){ ret = 0; }
1826    }
1827
1828    return ret;
1829  }
1830  
1831  
1832  public static String valueStringFromRxValue(InspcDataExchangeAccess.Inspcitem info, int nBytesString)
1833  {
1834    String value = null; 
1835    value = info.getChildString(nBytesString);
1836    return value;  
1837  }
1838  
1839  
1840  
1841  /**Gets the reflection type of the received information.
1842   * 
1843   * @param info
1844   * @return The known character Z, C, D, F, B, S, I, J for the scalar types, 'c' for character array (String)
1845   */
1846  public static short getInspcTypeFromRxValue(InspcDataExchangeAccess.Inspcitem info)
1847  {
1848    char ret = 0;
1849    short type = (short)info.getChildInt(1);
1850    return type;
1851  }
1852    
1853    /**Gets the type of the received information.
1854   * 
1855   * @param info
1856   * @return The known character Z, C, D, F, B, S, I, J for the scalar types, 'c' for character array (String)
1857   */
1858  public static char getTypeFromInspcType(int type)
1859  {
1860    final char ret;
1861    if(type >= InspcDataExchangeAccess.kScalarTypes){
1862      switch(type - InspcDataExchangeAccess.kScalarTypes){
1863        case ClassJc.REFLECTION_char16: ret = 'S'; break;
1864        case org.vishia.reflect.ClassJc.REFLECTION_char8:  ret = 'C'; break;
1865        case org.vishia.reflect.ClassJc.REFLECTION_double: ret = 'D'; break;
1866        case org.vishia.reflect.ClassJc.REFLECTION_float:  ret = 'F'; break;
1867        case org.vishia.reflect.ClassJc.REFLECTION_int8:   ret = 'B'; break;
1868        case org.vishia.reflect.ClassJc.REFLECTION_int16:  ret = 'S'; break;
1869        case org.vishia.reflect.ClassJc.REFLECTION_int32:  ret = 'I'; break;
1870        case org.vishia.reflect.ClassJc.REFLECTION_int64:  ret = 'J'; break;
1871        case org.vishia.reflect.ClassJc.REFLECTION_int:    ret = 'I'; break;
1872        case org.vishia.reflect.ClassJc.REFLECTION_uint8:  ret = 'B'; break;
1873        case org.vishia.reflect.ClassJc.REFLECTION_uint16: ret = 'S'; break;
1874        case org.vishia.reflect.ClassJc.REFLECTION_uint32: ret = 'I'; break;
1875        case org.vishia.reflect.ClassJc.REFLECTION_uint64: ret = 'J'; break;
1876        case org.vishia.reflect.ClassJc.REFLECTION_uint:   ret = 'I'; break;
1877        case org.vishia.reflect.ClassJc.REFLECTION_boolean:ret = 'Z'; break;
1878        default: ret = '?';
1879      }      
1880    } else if(type == InspcDataExchangeAccess.kReferenceAddr){
1881      ret = 'I';
1882    } else if(type == InspcDataExchangeAccess.kLengthAndString){
1883        ret = 'c';
1884    } else if(type <= InspcDataExchangeAccess.maxNrOfChars){
1885        ret = 'c';
1886    } else {
1887      ret = '?'; //error
1888    }
1889    return ret;
1890  }
1891  
1892  
1893  public int getStateInfo() {
1894    if(stateIdle.isInState()) return 1;
1895    else if(stateWaitAnswer.isInState()) return 2;
1896    else return 0;
1897  }
1898  
1899  
1900  /**Executes after the last answer telegram of this sequence was received. It checks all entries 
1901   * in {@link #callbacksOnAnswer} and executes it.
1902   * 
1903   */
1904  void lastTelg(){
1905    Set<Map.Entry<Integer, Runnable>> list = callbacksOnAnswer.entrySet();
1906    try{
1907      Iterator<Map.Entry<Integer, Runnable>> iter = list.iterator();
1908      while(iter.hasNext()){
1909        Runnable run = iter.next().getValue();
1910        run.run();   
1911      }
1912    } catch(Exception exc){
1913      System.err.println("InspcTargetAccessor - lastTelg wrong callback; " + exc.getMessage());
1914    }
1915    getFieldsData.bGetFieldsPending = false;  //maybe was true.
1916    callbacksOnAnswer.clear();
1917  }
1918  
1919  
1920
1921        
1922        
1923        
1924        @Override public String toString(){
1925          
1926          return name + ": " + targetAddr.toString() + ":" + state;
1927        }
1928        
1929        @Override public InspcTargetAccessData getTargetAccessFromPath(String sDataPath, boolean strict)
1930  { throw new RuntimeException("only valid for the manager.");
1931  }
1932
1933  
1934  
1935  InspcAccessExecRxOrder_ifc XXXactionRx4ValueByIdent = new InspcAccessExecRxOrder_ifc(){
1936    @Override public void execInspcRxOrder(InspcDataExchangeAccess.Inspcitem info, long time, LogMessage log, int identLog)
1937    { execRx4ValueByHandle(info, time, log, identLog);
1938    }
1939    @Override public Runnable callbackOnAnswer(){return null; }  //empty
1940  };
1941        
1942        void stop(){}
1943
1944
1945}