Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
sivantoledo committed Mar 11, 2012
0 parents commit a2b93cf
Show file tree
Hide file tree
Showing 27 changed files with 3,929 additions and 0 deletions.
Binary file added manual.doc
Binary file not shown.
162 changes: 162 additions & 0 deletions src/SoundcardInterface.java
@@ -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();
}
}
78 changes: 78 additions & 0 deletions src/SoundcardWriteThread.java
@@ -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();
}
}
}
138 changes: 138 additions & 0 deletions src/TNCConnectThread.java
@@ -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();
}
}
}
}
}

0 comments on commit a2b93cf

Please sign in to comment.