36  What’s changed since v3?

UnetStack v7 keeps the same architecture as UnetStack v3 — a stack of agents that implement services, accessed from the shell, Groovy scripts or the UnetSocket API — so most code, scripts and applications written for UnetStack v3 continue to work with little or no change. A number of things have changed, however: the composition of the default stack, the set of services, some message and parameter contracts, the shell commands for a few features, and the tooling that ships with the stack.

This appendix is not an exhaustive changelog. It summarizes the changes you are most likely to notice (or trip over) when coming from UnetStack v3, with migration guidance attached to each. Where the right action depends on something we could not confirm from the sources, it is flagged in a CHECK callout for you to verify against your own deployment.

36.1 Framework & versions

  • UnetStack is now at v7 (the handbook you are reading documents v7.0.1), up from the v3.x series. Most user-facing concepts (services, agents, messages, parameters, the shell, UnetSocket) are unchanged, so the migration effort is concentrated in the specific areas called out below rather than in a wholesale rewrite.
  • fjåge has been updated. UnetStack v7 ships with fjåge 2.5.0 and Groovy 2.5.23. If you depend on fjåge directly (for example, custom gateways or agents built against the fjåge API), rebuild against the bundled version and check for any fjåge API changes.
ImportantCHECK

Confirm the exact fjåge version your UnetStack v3 deployment used (and the minimum fjåge/ Java versions your own code targets) so you can assess the size of the fjåge upgrade. Also confirm whether any of your custom agents rely on Groovy language features that differ between the Groovy version bundled with UnetStack v3 and Groovy 2.5.23.

36.2 The default stack

The most visible change is in the agents that are loaded by default (etc/setup.groovy). The table below summarizes the default stack in each version:

Role UnetStack v3 (default) UnetStack v7 (default)
Link (uwlink) ReliableLink ECLink (erasure-coded)
Transport SWTransport (as transport) Caddy / CaddyLite (as caddy)
Remote access RemoteControl (as remote) folded into the caddy agent
State persistence (statemanager) StateManager removed (see below)
  • The default underwater link is now ECLink (uwlink). Where UnetStack v3 loaded org.arl.unet.link.ReliableLink as uwlink, UnetStack v7 loads org.arl.unet.link.ECLink. ECLink uses erasure coding to deliver datagrams faster and more robustly over the same channels, avoiding the per-fragment acknowledgement round-trips that ReliableLink relies on (Chapter 18). The uwlink name and the LINK + DATAGRAM service contract are unchanged, so code that sends DatagramReqs to uwlink keeps working.
    • Migration: no change needed for normal use. If you set ReliableLink-specific parameters (e.g. acks, reservationGuardTime), note that ECLink exposes a different parameter set (reliableExtra, unreliableExtra, fragmentLength, controlChannel/dataChannel, …, see Chapter 18). ReliableLink is deprecated but still available, so a deployment that genuinely needs it can load it explicitly:

      // bring back the old link, if you really need it
      container.add 'uwlink', new org.arl.unet.link.ReliableLink()
  • Transport and remote access are now one agent. UnetStack v3 used org.arl.unet.transport.SWTransport (loaded as transport) for the TRANSPORT service and a separate org.arl.unet.remote.RemoteControl agent (loaded as remote) for the REMOTE service. UnetStack v7 loads a single agent named caddy that provides the TRANSPORT, REMOTE and DATAGRAM services. The base implementation org.arl.unet.transport.CaddyLite is part of the standard distribution; the licensed org.arl.unet.transport.Caddy is a drop-in replacement that adds QoS (priority, TTL, fairness, rule-based routing) and resumable file transfers (Chapter 24). The shell still provides transport and remote handles that resolve to the agent through its services, so interactive usage reads the same as before.
    • Migration: shell usage is unchanged — ping, tell, rsh, fput/fget work as before, and remote shell/file operations are still gated by remote.enable = true on the node being accessed (Chapter 24). Code that looks agents up by service (agentForService(Services.TRANSPORT), agentForService(Services.REMOTE)) is unaffected. Code that hard-codes the class org.arl.unet.remote.RemoteControl or the agent name transport should look the agent up by service instead. SWTransport is deprecated but still available (Chapter 23) if you need the old stop-and-wait behavior.

      // robust: works in both versions
      def remote = agentForService Services.REMOTE
    • Remote acknowledgements work differently. The v3 ack on/ack off shell command, the ack field of RemoteTextReq and friends, and the ?-prefix trick for getting remote command output are all gone. In UnetStack v7, rsh sends the command output back by default (append a trailing ; to suppress it), tell takes an optional reliability argument (e.g. tell 31, 'hello', true), and the progress command reports on ongoing file transfers (Chapter 24). Scripts that use ack or ?-prefixed remote commands must be updated.

36.3 Services

The set of services in org.arl.unet.Services has changed. In UnetStack v7 the enum is:

NODE_INFO, ADDRESS_RESOLUTION, DATAGRAM, PHYSICAL, RANGING, BASEBAND, LINK, LINK_TUNING, MAC, ROUTING, ROUTE_MAINTENANCE, TRANSPORT, REMOTE, SCHEDULER, DEVICE_INFO, DOA.

  • New services in UnetStack v7. Three services have no UnetStack v3 counterpart:

    • LINK_TUNING — tuning of link parameters (Chapter 20).
    • DEVICE_INFO — device/hardware information such as storage and status (Chapter 28).
    • DOA — direction-of-arrival estimation (Chapter 26).
    • Migration: these are additive. Existing code is unaffected; new code can take advantage of them by looking up the relevant service (e.g. agentForService(Services.DEVICE_INFO)).

    All other UnetStack v3 services (DATAGRAM, PHYSICAL, BASEBAND, RANGING, NODE_INFO, ADDRESS_RESOLUTION, LINK, MAC, ROUTING, ROUTE_MAINTENANCE, TRANSPORT, REMOTE, SCHEDULER, and the fjåge SHELL service) carry over unchanged, with the sole exception of STATE_MANAGER:

  • The State Persistence service has been removed. UnetStack v3 had a dedicated state-persistence mechanism: a statemanager agent (org.arl.unet.state.StateManager) and a savestate shell command that wrote a saved-state.groovy file into the scripts folder, which was then re-loaded automatically on reboot. UnetStack v7 has no STATE_MANAGER service in the Services enum, does not load a state-manager agent in the default stack, and no longer ships the StateManager class or the savestate command. Instead, persistence is handled by the framework: agents that need to survive a restart persist their own state through fjåge’s Store API (org.arl.fjage.persistence.Store). For example, the Scheduler agent (Chapter 29) saves and restores its state with getStore() / store.put(...) / store.getById(...) rather than relying on a central state manager.

    • Migration:
      • If your workflow relied on savestate to snapshot a configured node, replace it. The recommended approach is to capture your node configuration in an etc/setup.groovy (or a startup .groovy script in scripts/) that sets the parameters you need at boot — this is explicit, reviewable and version-controllable.

      • If you wrote a custom agent that persisted state via the old StateManager, port it to persist its own state through the fjåge Store API. A sketch:

        import org.arl.fjage.persistence.Store
        
        // saving
        Store store = getStore()
        store.put(myState)
        
        // restoring (e.g. in startup())
        Store store = getStore()
        def myState = store.getById(MyState, 'state')
  • The Scheduler service has been redesigned. The UnetStack v3 sleep-schedule API — AddScheduledSleepReq, RemoveScheduledSleepReq, GetSleepScheduleReq, SleepScheduleRsp, the rtc parameter, and the addsleep/showsleep/rmsleep shell commands — is gone. UnetStack v7 schedules sleep/wake (and arbitrary tasks) through SleepReq, StayAwakeReq and AddScheduledTaskReq, with sleep, cronadd, crontab and cronrm shell commands (Chapter 29).

    • Migration: v3 sleep-schedule scripts break silently (the commands no longer exist); rewrite them against the new commands/messages. Epoch-time-based one-shot sleeps map naturally onto sleep; recurring schedules onto cronadd.

36.4 Messages & parameters

A few message and parameter contracts changed between v3 and v7. These are the most common causes of silently-broken v3 code:

  • Datagram notifications are delivered on a global topic. In UnetStack v3, each DATAGRAM provider published DatagramNtfs on its own agent topic (so you would subscribe phy or subscribe uwlink to receive data), and frames overheard from other nodes were published on a separate SNOOP sub-topic (topic(phy, Physical.SNOOP)). In UnetStack v7, this is inverted: datagrams addressed to your node (or broadcast) appear on the global Topics.DATAGRAM topic, while the provider’s own agent topic carries frames overheard from other nodes (Chapter 16, Chapter 17). The Physical.SNOOP constant no longer exists.
    • Migration: code that subscribes to a provider’s topic to receive its own data must subscribe to topic(org.arl.unet.Topics.DATAGRAM) instead; code that used the SNOOP sub-topic should subscribe to the provider’s agent topic.
  • DatagramCancelReq is now CancelReq. Same role (cancel a pending datagram by message ID), new name.
  • Raw frames and collision notifications are gone. TxRawFrameReq and CollisionNtf no longer exist in the PHYSICAL service.
  • Several phy parameters moved or were removed. propagationSpeed, refPowerLevel, rxSensitivity, errorDetection, llr and janus are no longer phy/phy[] parameters; the power-reference and signal-level parameters now live on the baseband agent (bb.*, see Chapter 27).
  • JANUS moved to the AUX channel. In UnetStack v3, JANUS was transmitted as frame type 3 (enabled via the janus channel parameter); in UnetStack v7 it is carried on the AUX channel alongside other standardized schemes (Section 17.9).
  • Node orientation conventions changed. The v3 nodeinfo parameters heading (0° = North, measured clockwise) and turnRate are replaced by yaw (0° = East, measured anticlockwise) and yawRate (Chapter 14). Simulation scripts using the v3 motion-model properties must be updated to the new names and the new angle convention.

36.5 Shell, scripting & APIs

  • The shell is unchanged in spirit. It still accepts Groovy, agents are still reachable by name (e.g. router, caddy) or shell handles (transport, remote), and providers can still be located by service with agentForService(Services.<NAME>). Most UnetStack v3 shell scripts run unchanged. Watch for the specific command/agent changes above: anything tied to the old remote agent class, the old link/transport classes, savestate, addsleep, or ack.
  • Java packages are unchanged. Services and most agents keep their UnetStack v3 package names under org.arl.unet.* (e.g. org.arl.unet.Services, org.arl.unet.nodeinfo.NodeInfo, org.arl.unet.addr.AddressResolution, org.arl.unet.net.Router). The changes are at the level of which agent class is loaded by default (e.g. ECLink vs ReliableLink, Caddy/CaddyLite vs SWTransport), not a blanket package rename.
  • FSMBuilder moved to fjåge. UnetStack v3 provided org.arl.unet.FSMBuilder, which custom agents typically picked up through import org.arl.unet.*. That class has been removed in favor of the identical org.arl.fjage.groovy.FSMBuilder — add an explicit import org.arl.fjage.groovy.FSMBuilder to any agent that builds FSMs with it (the org.arl.fjage.* star import does not cover the subpackage). As a bonus, FSM definitions can now be statically compiled (see Chapter 33); avoid building FSMs inside non-static inner classes — use a static nested class with an explicit reference to the agent.
  • The UnetSocket API is preserved. UnetSocket remains available across Java, Groovy, Python (and the other supported language bindings), with the same connect/send/receive model. Applications written against UnetSocket for UnetStack v3 should port with little or no change.
    • Migration: rebuild against the UnetStack v7 libraries and re-run your tests. Prefer locating agents by service rather than by class name so that the default-stack agent swaps above do not affect you.
ImportantCHECK

Confirm there are no breaking changes in the UnetSocket client libraries / fjåge gateway protocol between the version your applications were built against and UnetStack v7 (2.5-era fjåge). In particular, verify the Python unetpy/fjagepy versions you use are compatible, and re-test any C or Julia bindings. If you maintain custom agents, also verify that the UnetAgent lifecycle hooks and parameter-declaration conventions you use match those documented in Part III and the developer chapters in Part IV.

36.6 Tooling & editions

  • The web IDE is gone. UnetStack v3 shipped a simulator IDE (bin/unet sim) with a file browser, script editor, simulation shell and a map view of the simulated network. UnetStack v7 drops it: simulations are run from the command line (bin/unet <script.groovy>, see Chapter 34), and each simulated node exposes its own web shell for interactive use. Files on a node (scripts, agent classes) can still be created and edited through the node’s web interface.
  • Unet audio is not included in the community release. The soundcard-based acoustic modem (Unet audio) that UnetStack v3 bundled in its community download is available only in the commercial editions of UnetStack v7. The community release still includes the full simulator, which is what this handbook’s examples run on.

36.7 Quick checklist

When moving a UnetStack v3 deployment or project to UnetStack v7:

  1. Rebuild against the UnetStack v7 / fjåge 2.5 libraries.
  2. Stop referencing deprecated/removed classes directly — look up agents by service (agentForService(...)) instead of by class. Affected: the link (ReliableLinkECLink), transport (SWTransportCaddy/CaddyLite as caddy) and remote (RemoteControl → folded into caddy).
  3. Update datagram subscriptions: subscribe phy/subscribe uwlinksubscribe topic(Topics.DATAGRAM); topic(phy, Physical.SNOOP) → the provider’s agent topic.
  4. Rename DatagramCancelReqCancelReq; remove any use of TxRawFrameReq/ CollisionNtf; move phy power/sensitivity parameter accesses to bb.*.
  5. Add import org.arl.fjage.groovy.FSMBuilder to any custom agent that builds FSMs with FSMBuilder (previously org.arl.unet.FSMBuilder, reachable via import org.arl.unet.*).
  6. Replace any savestate/StateManager usage with an explicit setup.groovy/startup script for configuration, and with the fjåge Store API for custom-agent state.
  7. Rewrite sleep schedules: addsleep/showsleep/rmsleepsleep/cronadd/crontab/ cronrm.
  8. Drop ack on/ack off and ?-prefixed remote commands — rsh returns output by default (trailing ; suppresses it).
  9. Update motion-model properties: heading/turnRateyaw/yawRate, converting to the new angle convention (0° = East, anticlockwise).
  10. Review parameters you set on uwlink and the transport agent, since the default agents expose different parameter sets from their v3 predecessors.
  11. Re-test your applications and shell scripts end-to-end, and address the CHECK items above for your specific deployment.