001/* 002 * Copyright (c) 2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-08-24 22:48:48 +0000 (Mon, 24 Aug 2015) $' 007 * '$Revision: 33634 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.ROADnet; 031 032import com.brtt.antelope.Orb; 033import com.brtt.antelope.OrbPacketChannel; 034import com.brtt.antelope.OrbWaveformPacket; 035 036import ptolemy.actor.TypedAtomicActor; 037import ptolemy.actor.TypedIOPort; 038import ptolemy.data.DoubleToken; 039import ptolemy.data.IntToken; 040import ptolemy.data.StringToken; 041import ptolemy.data.expr.Parameter; 042import ptolemy.data.type.BaseType; 043import ptolemy.kernel.CompositeEntity; 044import ptolemy.kernel.util.IllegalActionException; 045import ptolemy.kernel.util.NameDuplicationException; 046 047/** 048 * This actor connects to an Antelope ORB and collects packets matching the 049 * given sourcename, supplying samples from waveform packets to the channels of 050 * the output port. Waveforms encapsulated as GEN and GENC will always go to 051 * channel 0 of the output port. MGENC packets may contain multiple channels, 052 * and the samples are sent to channels 0, 1, 2, ... up to the number of 053 * channels contained. Make sure that the relation connected to the output port 054 * has its "Width" parameter set properly! 055 * 056 * @see OrbPacketSource 057 * @see OrbWaveformSink 058 * @see Orb 059 * @author Tobin Fricke, University of California 060 * @version $Id: OrbWaveformSource.java 33634 2015-08-24 22:48:48Z crawl $ 061 * @Pt.ProposedRating Red (tobin) 062 */ 063 064public class OrbWaveformSource extends TypedAtomicActor { 065 /** 066 * @param container 067 * The container. 068 * @param name 069 * The name of this actor. 070 * @exception IllegalActionException 071 * If the actor cannot be contained by the proposed 072 * container. 073 * @exception NameDuplicationException 074 * If the container already has an actor with this name. 075 */ 076 public OrbWaveformSource(CompositeEntity container, String name) 077 throws NameDuplicationException, IllegalActionException { 078 super(container, name); 079 080 output = new TypedIOPort(this, "output", false, true); 081 output.setMultiport(true); 082 output.setTypeEquals(BaseType.INT); 083 084 times = new TypedIOPort(this, "times", false, true); 085 times.setMultiport(false); 086 times.setTypeEquals(BaseType.DOUBLE); 087 088 orbname = new Parameter(this, "orbname"); 089 srcname = new Parameter(this, "srcname"); 090 091 orbname.setTypeEquals(BaseType.STRING); 092 srcname.setTypeEquals(BaseType.STRING); 093 094 _attachText( 095 "_iconDescription", 096 "<svg>" 097 + " <rect x=\"-30\" y=\"-20\" width=\"60\" height=\"40\" " 098 + " style=\"fill:white\"/> " 099 + " <circle cx=\"0\" cy=\"0\" r=\"15\" style=\"stroke:black\"/> " 100 + " <text x=\"-10\" y=\"-5\">Orb</text>" + "</svg>"); 101 } 102 103 /** Initialize the component and connect to the ORB. */ 104 105 public void initialize() throws IllegalActionException { 106 System.out.println("OrbWaveformSource: initialize"); 107 try { 108 super.initialize(); 109 _orb = new Orb(StringToken.convert(orbname.getToken()) 110 .stringValue(), "r"); 111 _orb.select(StringToken.convert(srcname.getToken()).stringValue()); 112 _orb.after(0); 113 } catch (Exception e) { 114 throw new IllegalActionException(this, "Couldn't connect to Orb." 115 + " (" + e.getMessage() + ")"); 116 } 117 118 } 119 120 /** 121 * Reap one packet from the ORB and distribute the samples contained in 122 * channels to the output port. 123 */ 124 125 public void fire() throws IllegalActionException { 126 super.fire(); 127 try { 128 129 OrbWaveformPacket pkt = (OrbWaveformPacket) (_orb.reap(true)); 130 /* Is there a better way to warn the user of situations like this? */ 131 132 if (pkt.channels.size() != output.getWidth()) { 133 _debug("Packet received from ORB contains " 134 + pkt.channels.size() 135 + "channels, but output port contains " 136 + output.getWidth() + " channels."); 137 } 138 139 for (int c = 0; c < pkt.channels.size(); c++) { 140 OrbPacketChannel channel = (OrbPacketChannel) (pkt.channels 141 .get(c)); 142 for (int n = 0; n < channel.nsamp; n++) { 143 output.send(c, new IntToken(channel.data[n])); 144 145 /* 146 * We only broadcast the timestamps corresponding to channel 147 * zero. I'm not sure whether this is the best plan. 148 */ 149 150 if (c == 0) 151 times.broadcast(new DoubleToken(channel.time + n 152 / channel.samprate)); 153 } 154 } 155 } catch (Exception e) { 156 throw new IllegalActionException(this, e.getMessage()); 157 } 158 159 } 160 161 /** 162 * The name of the orb to connect to, in the format "hostname:port". Note 163 * that orbnames.pf-style names are not supported -- you have to use a valid 164 * IP address or resolvable DNS name, and you have to use a numeric port 165 * number. 166 */ 167 public Parameter orbname; 168 169 /** 170 * The source name to request from the Orb. When this actor is initialized, 171 * orb.select() is called with the value of this parameter. 172 */ 173 public Parameter srcname; 174 175 /** 176 * Samples from incoming waveform packets appear on this port. For 177 * multiplexed packets (eg, MGENC format), the channels in incoming packets 178 * are mapped to the channels of this output port. In that case you should 179 * verify that the "width" property of the relation connected to this port 180 * is set to the expected number of channels. Also, rather than connecting 181 * multiple relations directly to this port, you should probably use a 182 * single "relation" object (black diamond), so that all of the channels are 183 * carried on the same relation. Then you can use the "Select" actor to 184 * access specific channels. 185 */ 186 public TypedIOPort output; 187 188 /** 189 * The timestamps for individual samples are output on this port. It's up to 190 * you to ensure that samples and their associated time stamps are consumed 191 * synchronously. At present, this is a single port and the times correspond 192 * to samples on channel zero of packets reaped from the Orb. Another 193 * possibility would be to demultiplex the times in a way analagous to the 194 * way samples themselves are distributed. Sample times are computed from 195 * the start time given in each packet and the sample rate. 196 */ 197 public TypedIOPort times; 198 199 private Orb _orb; 200 201}