Search code examples
communicationunetstack

How to write Modem Drivers for non-subnero modems?


How can i use the existing modems which is not subnero with UnetStack (basically is not support UnetStack natively) ? I was gone through the post in detailed, but unfortunately had bad compilation issues. Can anyone point me to right direction ?

Below is the detailed error i encountered:

BUG! exception in phase 'semantic analysis' in source unit 'Script66.groovy' The lookup for MyModemDriver caused a failed compilation. There should not have been any compilation from this call.

Here is my code:

import org.arl.fjage.*
import org.arl.unet.*
import com.fazecast.jSerialComm.*
import org.arl.unet.api.UnetSocket
import org.arl.unet.phy.RxFrameNtf
import org.arl.unet.phy.TxFrameNtf


class PopotoModemDriver extends UnetAgent {

    // Using UnetSocket to connect to network modem ('ip',port)
    def sock = UnetSocket('192.168.0.42', 1100)
    AgentID notify      // notification topic
    int plvl = 170      // default power level setting

    @Override
    void setup() {
        notify = topic()
        register Services.PHYSICAL
        register Services.DATAGRAM
    }


    @Override
    void shutdown() {
        sock.close()
    }

    @Override
    Message processRequest(Message req) {
        if (req instanceof DatagramReq) {
            String s = "AT+TX:" + req.to + "," + req.data.encodeHex() + "\n"
            byte[] b = s.getBytes()
            sock.writeBytes(b, b.length)
            add new OneShotBehavior({
                send new TxFrameNtf(req)
            })
            return new Message(req, Performative.AGREE)
        }
        return null
    }

    int getMTU() {
        return 32         // frame size
    }

    boolean getRxEnable() {
        return true
    }

    float getPropagationSpeed() {
        return 1500       // assume sound speed is 1500 m/s
    }

    int getTimestampedTxDelay() {
        return 0          // our modem doesn't support timestamped transmissions
    }

    long getTime() {
        return 1000*System.currentTimeMillis()    // use system clock for timing in µs
    }

    boolean getBusy() {
        return false
    }

    float getRefPowerLevel() {
        return 0          // our modem uses absolute power levels in dB re uPa @ 1m
    }

    float getMaxPowerLevel() {
        return 180        // our modem can transmit at max power level of 180 dB
    }

    float getMinPowerLevel() {
        return 120        // ... and a min power level of 120 dB
    }

    int getMTU(int ch) {
        return 32         // frame size
    }

    float getFrameDuration(int ch) {
        return getMTU(ch)/getDataRate(ch)
    }

    float getPowerLevel(int ch) {
        return plvl
    }

    int getErrorDetection(int ch) {
        return 0
    }

    int getFrameLength(int ch) {
        return getMTU(ch)   // fixed frame size
    }

    int getMaxFrameLength(int ch) {
        return getMTU(ch)   // fixed frame size
    }

    int getFec(int ch) {
        return 0
    }

    List getFecList(int ch) {
        return null
    }

    float getDataRate(int ch) {
        return 320.0      // data rate of 320 bps
    }

    float setPowerLevel(int ch, float x) {
        plvl = x
        if (plvl < getMinPowerLevel()) plvl = getMinPowerLevel()
        if (plvl > getMaxPowerLevel()) plvl = getMaxPowerLevel()
        String s = "AT+TPL:" + plvl + "\n"
        byte[] b = s.getBytes()
        sock.writeBytes(b, b.length)
        return plvl
    }


    @Override
    void startup() {
        sock.openPort()
        add new CyclicBehavior({
            int n = sock.bytesAvailable()
            if (n == 0) Thread.sleep(20)
            else {
                // data available
                byte[] buf = new byte[n]
                sock.readBytes(buf, n)
                parseRxData(new String(buf))
            }
        })
    }

    String data = ''

    void parseRxData(String s) {
        data += s
        int n = data.indexOf('\n')
        if (n < 0) return
        s = data.substring(0, n)
        data = data.substring(n)
        if (s.startsWith("AT+RX:")) {
            int addr = s.substring(6,9) as int
            byte[] bytes = s.substring(10).decodeHex()
            send new RxFrameNtf(
                    recipient: notify,
                    from: addr,
                    data: bytes,
                    bits: 8*bytes.length,
                    rxTime: 1000*System.currentTimeMillis()
            )
        }
    }


}

Solution

  • @manuignatius is right, Groovy complains about this when there is a syntax error in a dynamically loaded Groovy class.

    To get a more detailed stack trace on the error, you can manually invoke the Groovy compiler. Set your CLASSPATH environment variable to include all the jars in the lib folder in your local UnetStack installation. Then simply run groovyc MyModemDriver.groovy, and it should show you compilation errors, if any. The compiled .class file that is produced on successful compilation can then be copied to the classes folder in UnetStack/modem instead of the source code.