Permalink
Browse files

Initial import

  • Loading branch information...
0 parents commit a2b93cf59c8fa22a7bcd2c3aaa71905da40159be @sivantoledo committed Mar 11, 2012
Binary file not shown.
@@ -0,0 +1,162 @@
+import java.util.*;
+import java.io.*;
+import java.net.*;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.TargetDataLine;
+
+import com.ae5pl.nsutil.*;
+
+import javax.sound.sampled.*;
+import sivantoledo.ax25.*;
+
+/**
+ * An interface to Sivan Toledo's sound-card modem for javAPRSIGate.
+ * <BR>
+ * Some code used by permission from Roger Bille SM5NRK
+ */
+final public class SoundcardInterface extends TNCConnectThread
+ implements sivantoledo.ax25.PacketHandler
+{
+
+ private String soundin, soundout;
+ private int rate;
+ private int latency_ms;
+ //sivantoledo.ax25.Afsk1200 afsk;
+ sivantoledo.ax25.Afsk1200Modulator modulator;
+ sivantoledo.ax25.PacketDemodulator demodulator;
+ sivantoledo.ax25.Soundcard sc;
+
+ private int TXDelay = 20; // KISS specification default is 50 (= 500ms)
+ private int Persist = 255; // KISS specification default is 63 (p = 0.25)
+ private int SlotTime = 0; // KISS specification default is 10 (= 100ms)
+ private int FullDuplex = 0; // KISS specification default is 0 (= half duplex)
+ private int TXTail = 10; // KISS specification says this is obsolete
+
+ //private final nsByteArrayOutputStream inbuf = new nsByteArrayOutputStream(1024);
+
+ private TransmitController ptt;
+
+ SoundcardInterface()
+ {
+ version = "Soundcard Interface; Copyright © 2005 - Pete Loveall AE5PL;";
+ }
+
+ /**
+ * Closes the serial port connection.
+ */
+ public final synchronized void close()
+ {
+ }
+
+ /**
+ * Returns version info for inclusion on status page.
+ */
+ public String getVersion()
+ {
+ return version+"; Sivan Toledo 2012";
+ }
+
+ public synchronized void init(Properties configuration)
+ {
+ initParams(configuration);
+ if (firstTime)
+ {
+ firstTime = false;
+
+ //try {TNCPort = Integer.parseInt(configuration.getProperty("SoundcardTNCDevice", "1").trim());}
+ //catch (Exception e){System.err.println("Exception parsing KISSTNCPortNumber "+e.toString());}
+ //tncPort =(byte)((TNCPort-1)<<4);
+ try {TXDelay = (Integer.parseInt(configuration.getProperty("KISSTXDelay", "200").trim())/10);}
+ catch (Exception e){System.err.println("Exception parsing KISSTXDelay "+e.toString());}
+ try {Persist = Integer.parseInt(configuration.getProperty("KISSPersist", "255").trim());}
+ catch (Exception e){System.err.println("Exception parsing KISSPersist "+e.toString());}
+ try {SlotTime = (Integer.parseInt(configuration.getProperty("KISSSlotTime", "0").trim()));}
+ catch (Exception e){System.err.println("Exception parsing KISSPersist "+e.toString());}
+ boolean fulldux = false;
+ try {fulldux = Boolean.valueOf(configuration.getProperty("KISSFullDuplex", "false").trim()).booleanValue();}
+ catch (Exception e){System.err.println("Exception parsing KISSFullDuplex "+e.toString());}
+ if (fulldux) FullDuplex = 1;
+ try {TXTail = (Integer.parseInt(configuration.getProperty("KISSTXTail", "100").trim())/10);}
+ catch (Exception e){System.err.println("Exception parsing KISSTXTail "+e.toString());}
+
+ try {rate = Integer.parseInt(configuration.getProperty("SoundcardSampleRate", "9600").trim());}
+ catch (Exception e){System.err.println("Exception parsing SoundcardSampleRate "+e.toString());}
+
+ try {latency_ms = Integer.parseInt(configuration.getProperty("SoundcardLatency", "100").trim());}
+ catch (Exception e){System.err.println("Exception parsing SoundcardLatency "+e.toString());}
+
+ //if (!configuration.containsKey("SoundCardName"))
+ // configuration.put("SerialPortName", configuration.getProperty("KISSPortName", ""));
+ String soundcard = configuration.getProperty("SoundcardName", "default").trim();
+ soundin = configuration.getProperty("SoundcardInputName", "default").trim();
+ soundout = configuration.getProperty("SoundcardOutputName", "default").trim();
+ if (soundin.equals("default")) soundin = soundcard;
+ if (soundout.equals("default")) soundout = soundcard;
+
+ System.err.println("Starting up Afsk1200 modem on ["+soundin+", "+soundout+"] at "+rate+" samples/s");
+
+ try {
+ modulator = new sivantoledo.ax25.Afsk1200Modulator(rate);
+ demodulator = new sivantoledo.ax25.Afsk1200MultiDemodulator(rate,this);
+ //afsk = new sivantoledo.ax25.Afsk1200(rate, this);
+ modulator.setTxDelay(TXDelay);
+ } catch (Exception e) {
+ System.err.println("Afsk1200 constructor exception: "+e.getMessage());
+ System.exit(1);
+ }
+
+ String ptt_port = configuration.getProperty("PTTPort", "none").trim();
+ String ptt_signal = configuration.getProperty("PTTSignal", "RTS").trim();
+ if (!ptt_port.equals("none")) {
+ try {
+ ptt = new SerialTransmitController(ptt_port,ptt_signal);
+ System.err.println("Opened a serial PTT port: "+ptt_port);
+ } catch (Exception e) {
+ System.err.println("PTT initialization error: "+e.getMessage());
+ ptt=null;
+ }
+ } else {
+ System.err.println("Warning: No PTT port (okay for receive only or for VOX)");
+ }
+
+
+ sc = new sivantoledo.ax25.Soundcard(rate, soundin, soundout, latency_ms,
+ demodulator, modulator);
+ new Thread(this, "SoundInterface Read").start();
+ }
+ }
+
+ public void handlePacket(byte[] packet) {
+ try {
+ TNCInterface.AX25Packet tnc = new TNCInterface.AX25Packet((byte)0, packet);
+ if (tnc.restOfPacket.length > 0)
+ queue.putOnQueue(tnc);
+ }
+ catch (Exception e){}
+ }
+
+ public void run() {
+ //if (serial == null) return;
+
+ // Init TNC
+ try
+ {
+ writer = new SoundcardWriteThread(demodulator, modulator,
+ sc,
+ (double) Persist / 255.0,SlotTime,
+ ptt);
+ }
+ catch (Exception e)
+ {
+ System.err.println("Error initializing Soundcard "+e.toString());
+ return;
+ }
+
+ sc.receive();
+ }
+}
@@ -0,0 +1,78 @@
+import java.io.*;
+import java.util.*;
+
+import sivantoledo.ax25.TransmitController;
+
+import com.ae5pl.nsutil.*;
+
+final class SoundcardWriteThread extends TNCWriteThread {
+ //private sivantoledo.ax25.Afsk1200 afsk;
+ private sivantoledo.ax25.Soundcard sc;
+
+ private sivantoledo.ax25.PacketDemodulator demodulator;
+ private sivantoledo.ax25.PacketModulator modulator;
+
+ private double persistence; // CSMA access probability
+ private int slot_time; // wait between CSMA attemps in 10ms units
+
+ private TransmitController ptt;
+
+ SoundcardWriteThread(//sivantoledo.ax25.Afsk1200 afsk,
+ sivantoledo.ax25.PacketDemodulator demodulator,
+ sivantoledo.ax25.PacketModulator modulator,
+ sivantoledo.ax25.Soundcard sc,
+ double persistence, int slot_time,
+ TransmitController ptt
+ ) {
+ super();
+ this.ptt = ptt;
+ //this.afsk = afsk;
+ this.demodulator = demodulator;
+ this.modulator = modulator;
+ this.sc = sc;
+ this.persistence = persistence;
+ this.slot_time = slot_time;
+ setName("Soundcard Write Thread");
+ start();
+ }
+
+ public void run() {
+ // if (output == null) return;
+ for (;;) {
+ TNCInterface.AX25Packet outline = (TNCInterface.AX25Packet) queue
+ .getFromQueue();
+ if (outline == null)
+ return;
+
+ byte[] newpacket = outline.getAX25Packet();
+ if (newpacket == null) {
+ yield();
+ continue;
+ }
+ try {
+ //output.write(newpacket);
+ // does the packet include the CRC, or do we need to add it?
+ // the contstructor of Packet does add the CRC, so hopefully it it not
+ // included.
+
+ while (demodulator.dcd()) yield(); // wait for a channel that is not busy
+ while (Math.random() > persistence) {
+ try { sleep(10*slot_time); } catch (InterruptedException ie) {}
+ while (demodulator.dcd()) yield(); // wait for a channel that is not busy
+ }
+
+ modulator.prepareToTransmit(new sivantoledo.ax25.Packet(newpacket));
+ // key PTT
+ if (ptt != null) ptt.startTransmitter();
+ sc.transmit();
+ // unkey PTT; we have drained the audio buffer
+ if (ptt != null) ptt.stopTransmitter();
+
+ pace(outline);
+ } catch (Exception e) {
+ queue.putOnQueue(null);
+ }
+ yield();
+ }
+ }
+}
@@ -0,0 +1,138 @@
+import java.util.*;
+
+/**
+ * Override this class to do your connection initialization and read functions.
+ */
+abstract class TNCConnectThread extends TNCInterface implements Runnable
+{
+ final TNCQueue queue = new TNCQueue();
+ volatile TNCWriteThread writer = null;
+
+ protected String version;
+
+ protected boolean firstTime = true;
+
+ /**
+ * Returns version info for inclusion on status page.
+ */
+ public String getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * Determines if connected to physical interface.
+ */
+ public boolean isConnected()
+ {
+ if (writer == null)
+ return false;
+ return writer.queue.isEnabled();
+ }
+
+ /**
+ * Get next received packet.
+ * <P>
+ * Must be synchronized to enable wait for next packet.
+ *
+ * @return TNC2 formated packet, no cr or lf
+ */
+ public TNCInterface.AX25Packet receivePacket()
+ {
+ return queue.getFromQueue();
+ }
+
+ /**
+ * This puts a packet on the TNC receive queue.
+ * <P>
+ * Must be synchronized.
+ * The packet is in TNC2 format.
+ *
+ * @param packet Complete packet including TNC2 header.
+ */
+ public void sendInternetPacket(TNCInterface.AX25Packet packet)
+ {
+ queue.putOnQueue(packet);
+ }
+
+ /**
+ * Submit packet for transmission.
+ * <P>
+ * Must be synchronized to allow placing packet on queue.
+ * Do not delay the calling process.
+ * <P>
+ * The packet is in TNC2 format.
+ *
+ * @param packet Complete packet including TNC2 header.
+ */
+ public void sendPacket(TNCInterface.AX25Packet packet)
+ {
+ if (writer != null)
+ {
+ queue.putOnQueue(packet); // For logging
+ writer.queue.putOnQueue(packet);
+ }
+ }
+
+ /**
+ * Override this function with your operating code
+ */
+ abstract public void run();
+
+ protected void initParams(Properties configuration)
+ {
+ try {TNCWriteThread.TNCSpeed = Integer.parseInt(configuration.getProperty("TNCSpeed", "1200").trim());}
+ catch (Exception e)
+ {
+ System.err.println("Exception parsing TNCSpeed");
+ e.printStackTrace();
+ }
+
+ try {TNCWriteThread.TNCIMax = Integer.parseInt(configuration.getProperty("TNCIFieldMax", "256").trim());}
+ catch (Exception e)
+ {
+ System.err.println("Exception parsing TNCIFieldMax");
+ e.printStackTrace();
+ }
+
+ try {TNCWriteThread.TNCVias = Integer.parseInt(configuration.getProperty("TNCMaxVias", "7").trim());}
+ catch (Exception e)
+ {
+ System.err.println("Exception parsing TNCMaxVias");
+ e.printStackTrace();
+ }
+
+ if (firstTime)
+ {
+ String TNCInit = configuration.getProperty("TNCPortInit", "");
+ if (TNCInit.length() > 0)
+ {
+ try
+ {
+ boolean waitforend = true;
+ try {waitforend = Boolean.valueOf(configuration.getProperty("TNCPortInitWait", "true").trim()).booleanValue();}
+ catch (Exception be)
+ {
+ System.err.println("Exception parsing TNCPortInitWait");
+ be.printStackTrace();
+ }
+ Process pr = Runtime.getRuntime().exec(TNCInit);
+ Thread tpo = new TNCProcMonitor(pr.getInputStream(), System.err);
+ Thread tpe = new TNCProcMonitor(pr.getErrorStream(), System.err);
+ if (waitforend)
+ {
+ pr.waitFor();
+ // The following are to ensure proper error log printing
+ tpo.join();
+ tpe.join();
+ }
+ }
+ catch (Exception e)
+ {
+ System.err.println("Error trying to run "+TNCInit);
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit a2b93cf

Please sign in to comment.