pastedGraphic

AppleScripting cocoaModem 2.0 

Kok Chen, W7AY [w7ay (at) arrl.net]
Last updated: January 14, 2009



Index


Introduction

cocoaModem does not pretend to be a digital interface for everybody; when there are multiple methods to get something done, cocoaModem will often implement only a single method.

cocoaModem also does not provide sophisticated contest nor logging facilities. I have tried to build decent demodulators for cocoaModem, but the area of user interfaces is neither a forte nor an interest of mine.

In an attempt to allow others to configure cocoaModem to their specific needs, I’d made cocoaModem’s source code completely free to non-commercial users. However, this still limits the audience of people to programmers who know how to get around in Cocoa.

For the non-programmer, I have added AppleScript support. This allows a wider set of people to create extensions for cocoaModem. It allows cocoaModem to inter-operate and share data with new, or with existing applications, including those that are written for other frameworks, such as Carbon or REALbasic.

As an example, whenever cocoaModem wishes to transmit, it simply generates the needed waveform and cocoaModem sends the audio signal to the output device. It assumes that the presence of that audio signal will trigger a VOX mechanism, which in turn will key the transmitter. This is the simplest and most plug-and-play means to connect a Macintosh to an SSB transceiver, and is the only “push-to-talk” mechanism provided natively by cocoaModem. AppleScripts that are associated with the Transmit button are used to implement other push-to-talk schemes.


Sending AppleScript Messages to Other Applications

cocoaModem can be set up so that certain activities (e.g., pressing the Transmit button in the interactive interface, or pressing the Log button in the QSO strip) can cause user-defined AppleScript scripts files to be executed. This is the mechanism which allows the buttons to be user configurable.

Figure 1 shows the AppleScript tab in the cocoaModem Preferences panel (select Preferences inside the cocoaModem 2.0 menu in the menu bar, or use the Command-comma keyboard shortcut).

ASPrefs
Figure 1 - AppleScript Preferences

The User Defined PTT scripts are described in the PTT section of the manual. The QSO Log script is executed when the Log button in the control strip is depressed.

Each text field in this preference panel points to the path of a script file (QSO Log) or to a folder that contains the script files (User Defined PTT). The Browse button for each text field allows you to use a standard file dialog to find and select the file or folder to use. If a text field is empty, no script will be executed for that action.

These script files are read, compiled and cached as NSAppleScript objects when cocoaModem initializes. They are recompiled and re-cached whenever the name of the Applescript file is changed.


QSO Log

The QSO Info bar (see cocoaModem User’s manual) of the interactive interface has a Log button which is usually disabled and gray out. This button becomes enabled when the Log button is linked to a script file through the AppleScript preference described above. The Log button executes this script when it is pushed. The script can for example fetch certain data from cocoaModem and send those to a second scriptable program.


Receiving AppleScript Messages from Other Applications

Figure 2 below shows cocoaModem’s AppleScript class hierarchy.

classes
Figure 2 - cocoaModem AppleScript Hierarchy

As usual, cocoaModem 2.0 is reached from an application tell block. The following is an example script. The rest of this section looks at each class in more detail.


tell application “cocoaModem 2.0”
tell rtty modem
tell transceiver 1
set enable to true
set properties of receiver to { mark:2295.0, space:2125.0 }
set properties of transmitter to { mark:2125.0, space:2295.0 }
end tell
end tell
select rtty modem
select contest interface
end tell




cocoaModem Interfaces

The cocoaModem interface can be either an interactive interface or a contest interface.

(Note: these two interfaces are the same ones as presented in the Interface menu in the main cocoaModem menu bar.)

The cocoaModem interface that is shown on the desktop is selected by one of the following:


select interactive interface
select contest interface




Interface Window Color

The background color of a non-textured window can be changed by


tell application “cocoaModem 2.0”
set backgroundColor of interactive interface to { 60000, 65535, 60000 }
end tell


The three numbers represent respectively the red, green and blue components in RGB Color Space. 0 is the minimum value and 65535 (16-bit unsigned integer) is the maximum value.


Modems

The two interfaces (interactive and contest interfaces) share a set of modems, and the modems can be the RTTY, the dual RTTY, the wideband RTTY, the PSK, the Hellschreiber, the CW or the MFSK modem. Each modem is controlled by addressing them through their parent interfaces.

Modem interfaces are known by their names (in the cocoaModem main window's tabs), e.g. rtty modem, wideband rtty modem, dual rtty modem, psk modem, hellschreiber modem, cw modem or mfsk modem . You can select them for example by:



tell application “cocoaModem 2.0”
select dual rtty modem
end tell



or


tell application “cocoaModem 2.0”
select hellschreiber modem
end tell



The currently selected modem interface can be found by


tell application “cocoaModem 2.0”
get modemName
end tell



modemName returns a text string that is one of

“rtty modem”
“wideband rtty modem”
“dual rtty modem”
“psk modem”
“hellschreiber modem”
“cw modem”
“mfsk modem”


Transceivers

Each modem contains pairs of transmit and receive modules in the form of a transceiver. The RTTY modem has one transceiver, and the Dual RTTY, wideband RTTY, PSK and CW modems have two transceivers each.

Each transceiver is further partitioned into a transmitter and a receiver module, which we will see later.

Each transceiver has a transmit state, a modulation mode and an enable state to turn it on (receiver active) or off (receiver inactive).

You can query the transceiver that is currently active with the selectedTransceiver property, e.g.,


tell application “cocoaModem 2.0”
get selectedTransceiver of wideband rtty modem
end tell



selectedTransceiver returns 1 if the Xcvr 1 or Main transceiver is chosen, and selectedTransceiver returns 2 if Xcvr 2 or Sub transceiver is chosen. For modem interfaces that only have a single transceiver, selectedTransceiver returns 1 always.


Modulation Mode

With the PSK modem, the specific modulation mode of a transceiver can be selected to BPSK31, QPSK31, BPSK63, QPSK63, BPSK125 and QPSK125. For example


tell application “cocoaModem 2.0”
tell psk modem
set modulation of transceiver 1 to BPSK31
end tell
end tell



The above an also be written as:


tell application “cocoaModem 2.0”
set modulation of transceiver 1 of psk modem to BPSK31
end tell



With Hellschreiber, you can select Feld, FM105 and FM245 as the modulation modes, e.g.,


tell application “cocoaModem 2.0”
set modulation of transceiver 1 of hellschreiber modem to Feld
end tell



With MFSK, you can at present only select MFSK16 as the modulation mode, e.g.,


tell application “cocoaModem 2.0”
set modulation of transceiver 1 of mfsk modem to MFSK16
end tell



The modulation property is not presently used in the RTTY or CW modems.


Transceiver Enable

When enabled, a transceiver will demodulate and decode the incoming data to its receiver’s text stream. An enabled transceiver is also capable of being set into the transmitting state.

Setting enable to true is equivalent to setting the state of the modem to “active” in the modem’s receive config panel.


tell application “cocoaModem 2.0”
set enable of transceiver 1 of psk modem to true
end tell



The enable state can be read back using


tell application “cocoaModem 2.0”
get enable of transceiver 1 of mfsk modem
end tell



Note: since the two transceivers of the PSK modem share the same A/D converter, you can set the enable state of the PSK modem using either transceiver 1 or transceiver 2. The two channels of the Dual RTTY, wideband RTTY and CW modems have separate A/D converters and each transceiver can be independently enabled or disabled.

Transmit State

The state of a transceiver can either be receive or transmit.


tell application “cocoaModem 2.0”
set state of transceiver 1 of psk modem to transmit
end tell



Care should be taken to ensure that only one transceiver of one modem is in the transmit state, otherwise the output tones will be mixed and sent to the radio as separate PSK signals!

Note: for the PSK, CW, Hellschreiber and MFSK modems, the center frequency has to be selected (either by clicking on the waterfall or by sending the set frequency AppleScript to the modem) before the modem will switch to the transmit state. The frequencies of both the receiver and transmitter modules have to be set even though the transmission is only done through the transmitter.

Flush

If the modem is in the transmit state, any text characters in the transmitter module that has not yet started will be flushed away with the flush command. If the modem is not transmitting, all text in the transmitter module that is waiting to be sent out is discarded.


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
flush transmitter
end tell
end tell



Likewise, text in the receiver module’s buffer can be flushed. This causes subsequent get text requests to return empty strings until new text has been decoded by the demodulator.


Receiver and Transmitter Modules

Each transceiver consists of a receiver and a transmitter, each with a set of properties. For example, the following script will set the offset frequency of the receiver module of the psk transceiver:


tell application “cocoaModem 2.0”
tell transceiver 1 of psk modem
tell receiver
set frequency to 1070
end tell
end tell
end tell



The above script can also be written as:


tell application “cocoaModem 2.0”
set frequency of receiver of transceiver 1 of psk modem to 1070
end tell



Frequency Property of Module

frequency is a floating point value.

In an RTTY modem, this property is the same as mark, and specifies the Mark frequency of the AFSK signal.

In a PSK modem, this parameter specifies the frequency of the audio carrier tone of the PSK signal. Note that the PSK modem returns a -1.0 if the frequency has not been set.

Setting the property of a PSK receiver module to zero will deselect the particular channel (similar to a shift-click on the waterfall). However, even if the receiver is deselected, transmission is possible as long as a legitimate tone is sent to the transmit module.

Note that in PSK mode, the frequency property will be different from the frequency shown on the waterfall scale unless the Dial Readout in the PSK config panel has been set to Upper Side Band with 0 offset.


Mark and Space Frequencies

mark and space are floating point values which specify the Mark and Space frequencies of an RTTY signal.

These properties are not used by non-RTTY modems.

With an LSB transceiver, with standard amateur RTTY conventions, the space frequency of a standard RTTY signal is 170 Hz higher than the mark frequency.


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
tell transmitter
set mark to 2125.0
set space to 2295.0
end tell
end tell
end tell




Baud Rate

baud is a floating point value which specifies the baud rate an RTTY signal.

This property is not used by non-RTTY modems.

The conventional amateur RTTY baud rate is 45.45 baud (usually just called “45 baud”), determined by the 22 millisecond bit timing of the Baudot characters.

Even though it is rare to see anything other than 45 baud operation in the amateur bands, there have been occasions where hams have been known to use other baud rates. P5/4L4FN had operated for a period at 50 baud, and there used to be a high speed RTTY contest conducted at 75 baud.

The mark frequency, space frequency and the baud rate can be set with a single set properties command:


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
set properties of transmitter to { mark:2125.0,space:2295.0,baud:45.45 }
end tell
end tell




Invert

invert is an integer value (0 or 1) which specifies the inverted state of an RTTY tone pair.

This property is not used by non-RTTY modems.

Under standard amateur RTTY conventions, the space frequency an LSB transceiver is 170 Hz higher than the mark frequency. Inverting the signal will reverse the relative position of the tone pairs.


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
set invert of transmitter to 0
set invert of receiver to 1
end tell
end tell




Break-in

breakin is an integer value (0 or 1) which specifies if semi-break in is selected

This property is only currently used in the CW interface and it only applies to the transmit module.

To get the break-in state of the CW interface,


tell application “cocoaModem 2.0”
tell transceiver 1 of cw modem
breakin of transmitter
end tell
end tell



To set the break-in state of the CW interface


tell application “cocoaModem 2.0”
tell transceiver 1 of cw modem
set breakin of transmitter to 1
end tell
end tell



If the AppleScript breakin property is asserted, anything sent to the module's stream will cause the PTT to assert and the character(s) in the stream to be immediately transmitted.

Stream

Each module of a modem is associated with a text string called the stream.

Text is added by cocoaModem to the receiver modules’ streams as they are demodulated and decoded. The AppleScript client periodically polls the stream for new characters. An empty string is returned if there are no new received characters.

Since RTTY is sent at 6 characters per second, when polled at a slower rate than 6 per second, the returned RTTY modem’s stream can contain more than one character.

Each text string is a portion of a 256 character circular buffer. If the module is not polled often enough, the buffer can wrap around, causing text to be lost.

To transmit text, the client adds characters to the transmitter module of a transceiver by setting the stream string:


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
set stream of transmitter to “\nCQ CQ\n”
end tell
end tell



For example, the following AppleScript can be used to transmit a quick CQ message over RTTY:


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
set state to transmit
set stream of transmitter to “\nCQ CQ\n”
set state to receive
end tell
end tell



When the transceiver is in the transmit state, the string will be immediately sent to the transmit stream. Otherwise, it will be buffered and will be sent the next time the modem is placed in the transmit state.

Text that has been sent to the modulator can be read back by performing a get on the transmit text stream. This functions as an echo of characters as they are being transmitted.

As mentioned earlier, any text left in the transmit buffer can be flushed using the flush transmitter command.

The set stream AppleScript works with Hellschreiber, but you cannot read any stream from the receive module since Feld Hell and FM Hell are facsimile modes -- there is no decoded text stream to read back.


Replay (click buffer)

cocoaModem's PSK, wideband RTTY and wideband CW interfaces come with "click buffers." These are buffers which stores up to 20 seconds of wideband audio. Input from the sound card are written into the click buffer and data are read by the demodulators from the buffer. Two pointers determine where data is written into and where data is read from, acting in a ring buffer manner -- the ring's size accommodating about 20 seconds worth of audio.

As long as the consumer and producer pointers of the ring buffer are not identical, data is handed to the demodulators at about 8 times real-time rate.

The replay AppleScript allows the client to move the consumer pointer so that up to 20 seconds of "old" audio is replayed into the demodulator.


tell application “cocoaModem 2.0”
tell transceiver 1 of wideband rtty modem
set replay of receiver to 20.0
end tell
end tell



cocoaModem will treat the replay AppleScript as a no-op if it is sent to a modem that does not support a click buffer. A transmit module will also treat the replay AppleScript as a no-op.

The replay property, a floating point, will be truncated to 20 seconds if a larger value is sent to it. Values that are negative, or are smaller than 0.1 second are replaced by 0.1 second.


Spectrum

An AppleScript client can draw its own waterfall or panadaptor display by fetching the spectrum from the receive module of the wideband RTTY and PSK interfaces.

Please note for the present, only the spectrum of "transceiver 1" of the RTTY interface is available. The two PSK transceivers share a common waterfall, which can be obtain from "transceiver 1" of the PSK interface.

The following script can be used to fetch a spectrum:


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
get spectrum of receiver
end tell
end tell



This script returns a zero length string if an updated spectrum is not yet available. Otherwise, it returns a string of 1024 bytes. Each non-zero byte is treated as an unsigned 8-bit number.

The 1024 numbers represent FFT bins with a resolution of 2.692 Hz per bin. The 0-th byte contains the value of the DC bin and the 1023-rd byte contains the value of the FFT bin that is centered at approximately 2756 Hz (i.e., at 11025/4 Hz).

To compress the spectral height into a single unsigned byte, the values are encoded as the square root of the power (i.e., the fourth root of voltage) in each FFT bin.

The amplitude of each FFT bin is encoded with pow( v, 0.25 )*5.52. A full scale signal (when a narrow carrier causes the yellow bar in cocoaModem's VU meter to light up) is encoded into the value 200, a signal that is -30 dB from full scale is encoded as the value 35, etc. A clipped signal can exceed the nominal full scale signal and reach a value of about 234.

The waterfall in cocoaModem updates approximately every 371 milliseconds. While a new spectrum is not yet available, cocoaModem will respond to the get spectrum request by returning a string of length zero.

To help the client avoid needless polling, the next spectrum script returns an integer which gives an estimate of the number milliseconds before the next FFT spectrum becomes avalable.


tell application “cocoaModem 2.0”
tell transceiver 1 of rtty modem
get next spectrum of receiver
end tell
end tell



If next spectrum returns zero, another spectrum is immediately available to be fetched.

next spectrum returns a conservative estimate; 2.5 milliseconds is added to the scheduled time an FFT is next taken by cocoaModem. However, system latencies can cause next spectrum to return an estimate that is still too small. Because of this, get spectrum should always be checked to see if the length of the returned string is zero. If a string of length zero is returned by get spectrum, a new spectrum is not yet available and next spectrum should then be called again, followed by a delay it specifies. The next get spectrum should again be called only after this delay.

When cocoaModem is placed in transmit mode, no new spectrum will be returned until cocoaModem returns to the receive mode. In the transmit mode, next spectrum will always return the maximum delay (approx 374 msec). The algorithm given above will still work while cocoaModem is transmitting since it simply causes the client to re-poll cocoaModem every 374 milliseconds. When cocoaModem is later switched back to receive mode, the spectrum stream will automatically resume.


Windows and Panels

Some windows and panels in cocoaModem can be controlled through AppleScripts.

The main window (including the Lite window) can be made visible or invisible by setting the application's window state to true or false, respectively.


tell application “cocoaModem 2.0”
set window state to false
end tell



The main window position can also be read and set by addressing the window position property.


tell application “cocoaModem 2.0”
get window position
set window position to {15,200}
end tell



The position consists of two integers, representing the x and y locations of the bottom left corner of the window.

The Config panel of any modem can be brought up by sending open config panel to the modem.


tell application “cocoaModem 2.0”
tell psk modem
open config panel
end tell
end tell



In addition, the RTTY modem of the Lite interface has two auxiliary windows that can be displayed or hidden and their positions can also be read back or set.


tell application “cocoaModem 2.0”
tell wideband rtty modem
get controls position
set show controls to false
set spectrum position to { 500,100 }
set show spectrum to false
end tell
end tell



Setting show controls and show spectrum to true or false makes the controls window or spectrum window visible or invisible. The controls window is the one with the crossed ellipse indicator, and the spectrum window is the one with the spectrum of the input device (similar to the spectrum in the config panel).

Like the main window, the position consists of two integers, representing the x and y locations of the bottom left corner of the window.

version and scriptVersion

scriptVersion returns an integer. The current script version is 3.

version is a string (e.g., "0.90") that is the current version of cocoaModem 2.0. The version AppleScript is available from scriptVersion 3 onwards.


Watchdog Timer

There is a watchdog timer in cocoaModem that unkeys the transmitter when the duration exceeds a a limit. To prevent the watchdog time from firing, the timer can be reset periodically (once every 30 seconds is sufficient) using the reset watchdog AppleScript .


tell application “cocoaModem 2.0”
reset watchdog
end tell




QSO Info

The qso (QSO Info subclass) property of the application accesses the callsign and operator name text strings in cocoaModem’s QSO Info bar. Examples of its usage is


tell application “cocoaModem 2.0”
tell qso
set localString to callsign
end tell
end tell



Note that when a property is inside of a set of nested tell blocks, you can concatenate the classes by using one or more of directives and write the above more concisely as


tell application “cocoaModem 2.0”
set localString to callsign of qso
end tell



Similarly, the operator name field can be accessed using


tell application “cocoaModem 2.0”
get operator name of qso
end tell



Contest Interface

The band menu in cocoaModem’s read and set through an AppleScript. This allows an external rig control software to change the band menu.


tell application “cocoaModem 2.0”
get band of contest
set band of contest to 15
end tell



cocoaModem Suite Dictionary

The cocoaModem 2.0 AppleScript suite is defined in the file cocoaModem 2.0.sdef. The classes defined in the suite are application, interface, modem, module and QSO.

Commands

select - select a specific interface or modem (in application)

flush - flush transmit stream of modem (in module)

Classes

application - the cocoaModem application
Properties:
interactive / contest interface
rtty / dual rtty / wideband rtty / psk / hellschreiber / cw / mfsk modem
scriptVersion
version


modem - rtty / dual rtty / wideband rtty / psk / hellschreiber / cw / mfsk
Properties:
transceiver 1 / 2


transceiver - transceiver 1 / transceiver 2
Properties:
enable boolean
modulation bpsk31 / qpsk31 / bpsk63 / qpsk63 / bpsk125 | qpsk125 | mfsk16
state transmit / receive
flush module
module transmitter / receiver


module - transmitter / receiver
Properties:
frequency float
mark float
space float
baud float
invert int
breakin int
stream text


QSO Info - qso
Properties:
callsign text
operator name text


Contest - contest
Properties:
band int


Deprecated AppleScripts

The global AppleScript properties that were available in cocoaModem 1.15 are now deprecated.

In some future version of cocoaModem, these AppleScripts will no longer be accepted. It is being kept for the time being for users to transition to the new AppleScripts. The deprecated AppleScripts and their new equivalents are shown below.

modemMode
old: set modemMode to RTTY
use instead: select rtty modem

pskModulation
old: set pskModulation to BPSK31
use instead: set modulation of transceiver 1 of psk modem to bpsk31

pskRxAOffset
old: get pskRxAOffset
use instead: get frequency of receiver of transceiver 1 of psk modem

pskTxAOffset
old: get pskTxAOffset
use instead: get frequency of transmitter of transceiver 1 of psk mode

pskRxBOffset
old: get pskRxBOffset
use instead: get frequency of receiver of transceiver 2 of psk modem

pskTxBOffset
old: get pskTxBOffset
use instead: get frequency of transmitter of transceiver 2 of psk modem

qsoCall
old: get qsoCall
use instead: get callsign of qso

qsoName
old: get qsoName
use instead: get operator name of qso



Index