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}