View Javadoc

1   package de.desy.acop.video.displayer;
2   
3   import java.util.logging.Handler;
4   import java.util.logging.Level;
5   import java.util.logging.LogRecord;
6   import java.util.logging.Logger;
7   import java.util.logging.StreamHandler;
8   
9   import de.desy.acop.transport.ConnectionFailed;
10  import de.desy.acop.transport.ConnectionParameters;
11  import de.desy.tine.client.TLink;
12  import de.desy.tine.client.TLinkCallback;
13  import de.desy.tine.dataUtils.TDataType;
14  import de.desy.tine.definitions.TAccess;
15  import de.desy.tine.definitions.TFormat;
16  import de.desy.tine.definitions.TMode;
17  import de.desy.tine.queryUtils.TPropertyQuery;
18  import de.desy.tine.queryUtils.TQuery;
19  import de.desy.tine.types.IMAGE;
20  
21  /**
22   * <code>TineHandler</code> encapsulates and divides reception of VSv3 and VSv2
23   * image streams from displaying class ImageDisplayerTest. It implements probing
24   * of sources and reception, prearrangement and forwarding of video image blobs
25   * from TINE to displaying part.
26   * 
27   * @author <a href="mailto:stefan.weisse@desy.de">Stefan Weisse</a>
28   * @author <a href="mailto:david.melkumyan@desy.de">David Melkumyan</a>
29   * 
30   * @version $Id: Templates.xml,v 1.10 2008/06/23 15:30:13 sweisse Exp $
31   * 
32   */
33  public final class TineHandler implements TLinkCallback {
34  
35  	private static final String LOGGER_NAME = "TineVideo";
36  
37  	/**
38  	 * error code of 607 means for VSv2: currently no new image to be
39  	 * transferred (e.g. timeout on schedule)
40  	 */
41  	private static final int V2CODE_NO_DATA = 607;
42  
43  	/**
44  	 * error code of 516 means for VSv3: currently no new image to be
45  	 * transferred (e.g. timeout on schedule)
46  	 */
47  	private static final int V3CODE_NO_DATA = 516;
48  
49  	/** will get the prearranged images for further use. */
50  	private TineImageReceiver receiver;
51  
52  	/**
53  	 * temporary storage of next successfully received video image from TINE,
54  	 * also used to wrap VSv2 data blob as VSv3 image.
55  	 */
56  	private IMAGE srcImage;
57  
58  	/** VSv2 raw bits buffer. */
59  	private byte[] srcBufV2;
60  
61  	/** TINE video data transmission link. */
62  	private TLink tlink;
63  
64  	/** is a video data transfer running? */
65  	private boolean isTransfering;
66  
67  	/** should the ImageDisplayer be reset on next callback? */
68  	private boolean isResetReceiver;
69  
70  	/** is a VSv3 transfer ongoing? */
71  	private boolean isTransferV3 = true;
72  
73  	/** is an array image */
74  	private boolean isAImage = false;
75  
76  	public static final Logger logger;
77  
78  	static {
79  		logger = Logger.getLogger(LOGGER_NAME);
80  		LogFormatter formatter = new LogFormatter();
81  		Handler handler = new StreamHandler(System.out, formatter) {
82  			@Override
83  			public synchronized void publish(LogRecord record) {
84  				super.publish(record);
85  				flush();
86  			}
87  		};
88  		handler.setLevel(Level.INFO);
89  		logger.setLevel(Level.INFO);
90  		Handler[] handlers = logger.getHandlers();
91  		for (Handler h : handlers) {
92  			logger.removeHandler(h);
93  		}
94  		logger.addHandler(handler);
95  		logger.setUseParentHandlers(false);
96  	}
97  
98  	/** Constructor. The instance must always have a valid receiver-reference. */
99  	public TineHandler(TineImageReceiver receiver) {
100 		this.receiver = receiver;
101 	}
102 
103 	/**
104 	 * TINE callback implemented via TLinkCallback. It is called for each event
105 	 * on an asynchronous connection between image source and TineHandler class.
106 	 * Events can be new image delivery and error on image delivery property.
107 	 * 
108 	 */
109 	public void callback(TLink tlink) {
110 		logger.log(Level.FINE, "Tine Handler: update received.");
111 		if (!isTransfering) {// accidental callback-call
112 			logger.log(Level.INFO, "Tine Handler: Invalid update.");
113 			return;
114 		}
115 
116 		int cc = tlink.getLinkStatus();
117 		if (cc != 0) {
118 			logger.log(isNoData(cc) ? Level.INFO : Level.WARNING, //
119 					"Tine Handler: addr = \"/" + tlink.getFullDeviceNameAndProperty() // 
120 							+ "\", code = " + tlink.getLinkStatus() //
121 							+ ", msg = \"" + tlink.getLastError() + "\"");
122 			return;
123 		}
124 
125 		if (isTransferV3 == false) { // is currently a VsV2 transfer?
126 			// a good VSv2 blob was received, so marshal it inside a VSv3
127 			// object
128 			// if no error happens on marshalling, pass further downstream
129 			VideoHeaderV2 vidH2 = new VideoHeaderV2();
130 
131 			// do trick for camera port name, as it is not delivered with
132 			// oldfashioned VideoSystem v2 header
133 			String vidFrom = "'V2:/" + tlink.getContext() + "/" + tlink.getDeviceServer() + "'";
134 
135 			// "real" marshaling
136 			if (!vidH2.packageV2BlobIntoIMAGE(vidFrom, srcBufV2, srcImage)) { // error
137 				logger.log(Level.WARNING, "Tine Handler: Videotype V2 conversion failed, addr = " + vidFrom);
138 				System.err.println("Videotype V2 conversion failed, addr = " + vidFrom);
139 				return;
140 			}
141 		}
142 
143 		// on first call of callback method, the receiver is reset to allow
144 		// proper initialization of variables for following transfer
145 		if (isResetReceiver) {
146 			receiver.resetForReceiving();
147 			isResetReceiver = false;
148 		}
149 
150 		// pass video image along to receiver component
151 		receiver.updateValue(srcImage);
152 	}
153 
154 	/**
155 	 * Opens a one-time or permanent connection to an image source which can be
156 	 * a VSv3 component with output interface like SGP and CoreProvider or a
157 	 * VSv2 server like GrabServer2.
158 	 * 
159 	 * @param connParams
160 	 *            - connection parameters
161 	 * @throws ConnectionFailed
162 	 */
163 	public void openLink(ConnectionParameters connParams) throws ConnectionFailed {
164 		if (connParams == null)
165 			throw new NullPointerException("connParams == null!");
166 		logger.log(Level.INFO, "Tine Handler: Connecting to " + connParams.getRemoteName() + ".");
167 		TPropertyQuery[] infos = null;
168 		try {
169 			infos = TQuery.getPropertyInformation(connParams.getDeviceContext(), // 
170 					connParams.getDeviceGroup(), //
171 					connParams.getDeviceName(), //
172 					connParams.getDeviceProperty());
173 
174 		} catch (Exception e) {
175 			throw new ConnectionFailed("Probing Address did not succeed.", null);
176 		}
177 
178 		if (infos == null || infos.length == 0)
179 			throw new ConnectionFailed("Probing Address did not succeed.", null);
180 
181 		short type = infos[0].prpFormat;
182 		int size = infos[0].prpSize;
183 
184 		switch (type) {
185 		case TFormat.CF_BYTE:
186 			if (size <= 1)
187 				throw new ConnectionFailed("Illegal property data size: " + size, null);
188 			size -= VideoHeaderV2.HDRSIZE;
189 			isTransferV3 = false;
190 			break;
191 
192 		case TFormat.CF_AIMAGE:
193 			isAImage = true;
194 
195 		case TFormat.CF_IMAGE:
196 			isTransferV3 = true;
197 			break;
198 
199 		default:
200 			throw new ConnectionFailed("Unsupported data type: " + TFormat.toString(type), null);
201 		}
202 
203 		// create proper VSv3 buffer for
204 		// (a) receiving of VSv3 images
205 		// (b) passing along transformed VSv2 images to ImageDisplayer as VSv3
206 		// image
207 		// TODO sort out the length: prp.size is 10 times too large
208 		// srcImage = new IMAGE(V2_TRANSPORT_LENGTH);
209 		srcImage = new IMAGE(size);
210 
211 		// reset the receiver component on first successful callback!
212 		isResetReceiver = true;
213 
214 		// create tine link
215 		String address = "/" + connParams.getDeviceContext() + "/" + connParams.getDeviceGroup() //
216 				+ "/" + connParams.getDeviceName() + "/" + connParams.getDeviceProperty();
217 
218 		if (!isTransferV3) { // Vs2 data transferring
219 			int buffSize = size + VideoHeaderV2.HDRSIZE;
220 			if (srcBufV2 == null || srcBufV2.length != buffSize)
221 				srcBufV2 = new byte[buffSize];
222 			tlink = new TLink(address, new TDataType(srcBufV2), null, TAccess.CA_READ);
223 
224 		} else
225 			// Vs3 data transferring
226 			tlink = new TLink(address, //
227 					isAImage ? new TDataType(new IMAGE[] { srcImage }) : new TDataType(srcImage), //
228 					null, //
229 					TAccess.CA_READ);
230 
231 		// construct proper mode integer for attaching the link
232 		short tMode;
233 		switch (connParams.getAccessMode()) {
234 		case POLL:
235 			tMode = TMode.CM_POLL;
236 			break;
237 		case POLL_NETWORK:
238 			tMode = TMode.CM_POLL | TMode.CM_MCAST;
239 			break;
240 		case POLL_CONNECT:
241 			tMode = TMode.CM_POLL | TMode.CM_CONNECT;
242 			break;
243 		case READ:
244 			tMode = TMode.CM_SINGLE;
245 			break;
246 		default:
247 			throw new IllegalArgumentException("Illegal AccessMode: " + connParams.getAccessMode());
248 		}
249 
250 		if (tlink.attach(tMode, this, connParams.getAccessRate()) < 0) {
251 			tlink.cancel();
252 			tlink = null;
253 			throw new ConnectionFailed("No permanent connection to server (\"" + tlink.getLastError() + "\".", null);
254 		}
255 		logger.log(Level.INFO, "Tine Handler: Link established.");
256 		isTransfering = true;
257 	}
258 
259 	/**
260 	 * Return true if no new image, otherwise false
261 	 * 
262 	 * @param cc
263 	 *            - error code
264 	 * @return true if no new image, otherwise false
265 	 */
266 	private boolean isNoData(int cc) {
267 		return isTransferV3 ? (cc == V3CODE_NO_DATA) : (cc == V2CODE_NO_DATA);
268 	}
269 
270 	/**
271 	 * used to cancel a running transfer. Designed to work even in case no
272 	 * transfer was started at all.
273 	 * 
274 	 */
275 	public void closeLink() {
276 		logger.log(Level.INFO, "Tine Handler: Disconnecting.");
277 		if (tlink != null) {
278 			tlink.close();
279 			tlink = null;
280 		}
281 		isTransfering = false;
282 	}
283 
284 	// commented: mdavid
285 	// private String printError(TLink link) {
286 	// String retVal = "Link Error: addr = \"/" +
287 	// link.getFullDeviceNameAndProperty() //
288 	// + "\", code = " + link.getLinkStatus() //
289 	// + ", msg = \"" + link.getLastError() + "\"";
290 	// System.err.println(retVal);
291 	// return retVal;
292 	// }
293 }