JS8Call de KN4CRD2020-06-25 - v2.2 |
JS8Call stands on the shoulders of giants...the takeoff angle is better up there.
Read more on the original design inspiration here.
For release announcements and discussion, join the JS8Call mailing list here: https://groups.io/g/js8Call
JS8Call is a derivative of the WSJT-X application, restructured and redesigned for message passing using a custom FSK modulation called JS8. It is not supported by nor endorsed by the WSJT-X development group. While the WSJT-X group maintains copyright over the original work and code, JS8Call is a derivative work licensed under and in accordance with the terms of the GPLv3 license. The source code modifications are public and can be found in js8call branch of this repository: https://bitbucket.org/widefido/js8call/
JS8Call is and will always be open-source and free software (free as in beer and free as in speech, do with it what you like, for the sum of exactly $0).
You might be asking...why is this named JS8Call? Why was it renamed from FT8Call? Why not something else, like BACON or HF Messenger? Good question! It is named this way as an homage to its heritage:
Hence JS8 + Directed Calling = JS8Call. And in case you didn’t get that:
JS8Call currently comes in a variety of builds.
Binary downloads are available here: http://files.js8call.com/latest.html
Of course, you are always free to take a look at the source code as well!
In the application you can see the current time reported by your PC in UTC format. An accurate clock is important with JS8Call, as the decoder operates within a 15-second window of transmission (frames). Your clock being off greater than 2 seconds from UTC can cause messages to not decode at your station. It is best to use an Internet, NTP or GPS time source for synchronizing your clock as accurately as possible.
JS8Call includes an automatic and manual clock drift tool that you can use to modify your application time to match signals you see / hear (or to an external time source like a Timex watch, a handheld GPS device, WWV, or a rooster crowing). This is intended to be used as a fail-safe for when your synchronized time source is not available (like if you were out portable, away from internet connectivity).
NOTE: You do not actually have to have the exact time synchronized...just synchronized to the start of a transmission window (15, 10, or 6 seconds), +/- 2 seconds. Many operators can manually synchronize their system clock based on signals in the waterfall and the time drift reported for each station.
Make sure your rig is set to upper sideband (USB) mode for every band. If you are running lower sideband (LSB), you’ll likely see reversed signals you cannot decode.
The JS8 modulator is a constant envelope, full-duty modulation that transmits in 12.6 second frames in normal speed. Because of the dead air between transmission frames, multi-frame messages can be classified as 84% duty on a 15-second window (12.6 / 15 = 0.84) for normal and slow (25.28 / 30 = 0.84), 79% for fast on a 10-second window (7.9 / 10 = 0.79), 65% for turbo on a 6-second window (3.95 / 6 = 0.653), .
Please make note of the power restrictions your transceiver manufacturer recommends for full-duty digital transmissions. When in doubt, use only a maximum of 50% of your rig’s power output to “save your finals”.
Your input and output audio levels control how well you transmit and receive. Too high and the audio becomes distorted. Too low and you have no modulation / demodulation. Calibration is an important step to getting started.
A rule of thumb is to set your output audio just high enough to drive your transmitter while not engaging your ALC. If you drive your audio too high, your ALC will distort the tones and many stations will not be able to decode your transmissions.
For best decodes, it’s best to turn off your AGC (or set it to fast) and set your input audio just high enough to read somewhere around 30-40dB on the signal meter in the app. You might have to experiment with the settings that work best for your station and you might also have to engage your attenuator for strong signals.
TODO: We’ll eventually add an example here :)
If you’ve used FSQ, Fldigi or WSJT-X before, you’ll feel right at home with JS8Call. The premise is that JS8Call uses JS8 modulated messages, breaking up long free-text messages into multiple back-to-back transmission cycles with a few seconds of silence between “frames”.
JS8Call 2.0 introduced two new faster mode speeds for QSOs and 2.1 introduced a slow mode. The four speeds now available in JS8 are:
The intent of the faster speeds is to start your QSO in normal and "upgrade" to the faster speeds if conditions support it. If you have a modern PC with a performant CPU, you can optionally enable MULTI from the mode menu, allowing the decoder to decode all mode speeds at once.
Band activity is displayed on the left. Call activity (callsigns you've heard) are on the right. Right clicking will show a menu with an option to move your RX/TX offset to that audio frequency and send specific messages.
In the Call Activity, when a station responds to you a ★ indicator will be displayed next to their callsign. This helps you find, at a glance, other operators that are confirmed to be able to hear you.
When a station is calling CQ, a ☎ indicator will be displayed next to their callsign for 5 minutes. This helps you find, at a glance, other operators that are looking to make contact.
If a station has left you a message, a ⚑ indicator will be displayed next to their callsign. You can read that message by right clicking on the station and clicking “Show Message Inbox”.
Station distance and azimuth is computed from the first 6 digits of the maidenhead grid locators. This is an approximation describing an “area” on the map, not an exact point. JS8Call supports up to 12 digit locators for greater precision, but even then, the calculation will always remain an approximation.
There is a waterfall at the bottom of the screen to show you the signals in your audio passband. You can click on the waterfall to set your audio frequency offset.
There is also an option to change your VFO frequency (QSY) to center your selected audio offset to the rig passband center. This allows you to use narrow filters easily and is helpful for rigs with non-linear passbands.
By opening the waterfall controls (View->Show Waterfall Controls) you can configure your waterfall display, access a filtering feature (limiting which frequencies the decoder will try to decode), and the timing feature (allowing you to drift your local time sync to match a station).
The top yellow text box shows you messages that are either on the frequency offset you're on or who have directed a message to you (they sent a message that included your callsign).
You type into the white box on the bottom to prepare a message for transmission.
Normal FT8 character restrictions do not apply! The extended character set includes all printable uppercase ASCII (A-Z 0-9 Space ./?+-`~!@#$%^&*()_=[]\{}|;’:”,<>) and Latin 1 (¡¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ). The message structure is variable encoded, so the most common characters take the least amount of space, and special characters take longer to send.
As you type your message you’ll see the send button display the transmission time it’ll take to send your complete message. All you have to do is click send (or hit enter) to start transmitting on the next interval. As each frame is transmitted one after the other, the button will update with the amount of time left to transmit the message. JS8Call 2.0 supports typeahead, so you can start transmitting and continue typing your message as each frame is transmitted.Checksummed messages like MSG or Relays cannot use typeahead.
Because of this special variable encoding, messages in JS8Call cannot be decoded by WSJT-X. The same is also true, WSJT-X messages will not be shown in JS8Call.
Messages come in three forms:
Standard messages are free-text messages that do not start with a callsign or a directed command. These messages will only print at other station locations if they align their receive offset within 10Hz of your transmit offset. This operation is similar to other keyboard-to-keyboard digital modes, like Olivia, RTTY, and PSK.
Directed messages are special JS8Call transmissions that automatically prefix your message with your callsign, similar to how FSQCall operates. Directed messages are useful for communicating in that you do not have to include your callsign in your message, allowing you to use more of the transmission frame(s) for actual message text, as well as alerting the recipient that a message was sent to them. As long as you are in the same passband, you do not have to be on the same frequency offset to receive a directed message.
To send a directed message, all you need to do is include the callsign of the receiving station as the first word in the message or select a callsign in your heard list to have it automatically prefixed.
You’ll notice a special character at the end of the message, ala ♢ . This is a symbol to indicate the End of Transmission. JS8Call displays this as after the last frame of the message has been transmitted with nothing else to follow. This means you get a visual indicator that the transmission is done and you can begin transmitting a reply. This character can be customized in the Configuration.
Directed messages to you (and to @ALLCALL) are displayed in the top RX window.
When in the middle of receiving a directed message (i.e., after the first directed frame is received), your station will not respond automatically to commands (even with AUTO on) until that message is received or enough time has elapsed to move on (one minute from the last frame decoded).
Group directed messages are specially formatted JS8Call transmissions that announce your station via CQ or Heartbeats (HB) to the @ALLCALL and @HB callsign groups. They are directed at a group destination, but not generally to an individual station.
There is a special “@ALLCALL” group callsign that you can use to send the message to anybody who is able to receive your message. Some examples:
Group callsigns are a custom form of compound callsigns that begin with an “@” character, and can be up to 8 alpha-numeric (A-Z 0-9) characters in length.. If you modeled that in a regular expression, that would be:
[@][A-Z0-9\/]{0,3}[\/]?[A-Z0-9\/]{0,3}[\/]?[A-Z0-9\/]{0,3}
Group callsign functionality allows you to direct your message to anybody who has “joined” the group. You join the group by adding the group name to your settings. All stations who want to receive group messages must add the group to their station configuration. Stations without the group will still be able to see the message received in the band activity, but those messages will not be directed to them.
Say for example, I was part of the Georgia ARES group and I wanted to send other folks in the group a message, I’d send:
KN4CRD: @ARESGA QSL?
This group callsign will behave similarly to @ALLCALL. Everybody who has added the @ARESGA group to their station configuration will have the message printed on the screen. If instead, I transmitted:
KN4CRD: @ARESGA SNR?
Then, all group member stations who have AUTO enabled would respond with a signal report, similar to if you queried each group station individually.
There are a number of built-in group callsigns that can be transmitted just as efficiently as standard callsigns. All custom groups will require an extra frame during transmission:
Available are two “special” groups for spotting. When spotting stations receive messages to these @JS8NET and @APRSIS groups, the messages are posted to the JS8NET spotting server for processing. This allows for specialized functionality to be built to handle these messages. These groups are non-standard, so you cannot add them to your groups list for standard group processing. However, you can send messages to these groups directly (type it into your TX message box, save it to your saved messages, etc).
The @APRSIS group is an experimental feature allowing APRS messages to be spotted to the APRS-IS gateway. Two message commands are available, GRID for spotting your callsign at a specific location and CMD for sending a raw APRS packet.
For example, any station receiving my message:
KN4CRD: @APRSIS GRID FN04TV53
Will submit that spot to JS8NET and spot my callsign at that location to the APRS network. You would then be able to query that spot in an APRS client, like https://aprs.fi
To send a raw frame (say a direct APRS message to SMSGTE), we’d send:
KN4CRD: @APRSIS CMD :SMSGTE :@5551212 TEST
Everything after the CMD frame is forwarded in an APRS packet, like:
KN4CRD>APZJS8,qAS,KN4CRD::SMSGTE :@5551212 TEST
There are special directed messages that you can send to stations to have them automatically reply if they have AUTO enabled. They are comprised in the form of [CALLSIGN][COMMAND].
There are also a number of “short messages” that can be included in a directed message frame, which would be transmitted in one tx cycle with standard (non-compound, non-group) callsigns:
If we wanted to ask DR4CNK what their station information was, we’d send:
If we wanted to transmit a “relay” message to OH8STN through DR4CNK, we could use the relay command and send:
You can also mix and match standard and free text messages, but most of the time you won’t need to.
Directed messaging allows three commands to be used for message storage and retrieval at intermediate stations:
TODO: We’ll eventually add an example here :)
While AUTO is enabled, the software will automatically respond to directed queries, like “SNR?”, “INFO?”, and “GRID?”. When AUTO is turned off, JS8Call will buffer responses to directed queries in the send message textbox until you are ready to send the replies manually.
If you would like to participate in AUTO, but would not like to be responsible for message relays, you can disable relays while AUTO is enabled in the settings.
There’s a log item in the main menu of the application. You can also press F5 to start a log entry. The software will do its best effort to pre-populate log fields. However, you’ll likely have to fill out some missing information manually since the QSO is free-text and not automated.
The log is stored in JS8Call.log & JS8Call.adif in the log directory (which you can find by clicking “File -> Open log directory” in the main menu).
Currently, the logging function in JS8Call will log each contact, according to the ADIF spec, as MFSK mode and JS8 submode. There is also an option in the Logging settings to log the mode as DATA instead of MFSK & JS8.
Once logged, the selected directed callsign is automatically deselected by default, however this option can be overridden in the configuration.
When SPOT is enabled, JS8Call will report callsigns you hear (or your callsign if heard by other stations) to PSKReporter under the “JS8Call” mode.
JS8Call will also spot GRID commands with 6 or more characters. Make sure to set your grid locator to 6-12 characters for the most accurate spot. You can drill down with this map to your location if you’re unsure of your grid: http://k7fry.com/grid/. If you have a lat/lon, you can also use the lonlat2maiden script here: http://www.jidanni.org/geo/maidenhead/
There is an automated heartbeat mechanism that transmits on an interval. You can turn on the HB button by selecting “Enable Heartbeat Networking” from the mode menu. An HB button will then appear on the bottom left. This automated transmission will transmit your grid to the heartbeat network (directed to the @HB group callsign:
KN4CRD: @HB HEARTBEAT EM73 ♢
This interval at which the heartbeat transmits can be changed from the control menu or by right clicking the HB button. All heartbeats are transmitted on a random (unused) frequency offset between 500Hz-1000Hz to help prevent QRM. There is an option in the settings to allow heartbeating anywhere...which is especially useful on lower bands like 160m and 630m.
When you have AUTO replies enabled and you’ve selected to Send Heartbeat Acknowledgements, your station will send an ACK reply to signal to the other operator that you can hear them. These are essentially “lightweight heartbeats” from your station and will reset your heartbeat timer.
The intent of heartbeat is not to report on propagation. Instead it is to help populate your call activity (the heard list on the right) so you know who's likely to be reachable to make contact. You can't work them if you can't “hear” them (or if they cannot hear you).
Keep in mind, though, that HBs are not designed to start conversations. When you turn HB on, you’re “joining” the heartbeat network. This network allows for planning of relays and sending messages to be stored at those receiving stations. Think of HBs and ACKs as a way to plot network topology and relays (">") as a way to send messages to be read later (sort of like an SMS text message) through that network.
While heartbeating, if a station has a message to deliver to another station it hears heartbeating, it will announce that in a HEARTBEAT SNR, like so:
KN4CRD: KM4ACK HEARTBEAT SNR -12 MSG 32 ♢
You can then retreive that message using the “QUERY MSG” directed command:
KM4ACK: KN4CRD QUERY MSG 32
While in QSO (i.e., when you receive a transmission that is displayed in your incoming messages window) the HB timer will be reset to prevent your station from QRMing your QSO.
Also, keep in mind that unattended transmissions may be against the rules of your jurisdiction. To be most safe, heartbeat should only be automatically sent while you’re at the control point of your station. There’s an idle timer that you can configure in the settings that will disable your heartbeat once you leave your station idle (no mouse or keyboard movement).
NOTE: HBs are intentionally restricted to slow, normal and fast speeds for bandwidth efficiency and enhanced compatibility in the HB network.
The default way to call cq is with the “CQ CQ CQ” message. This is configured by default. What’s notable, though, is that you can configure this message in the settings. These are the messages supported to be sent in one frame transmission:
When using one of these message formats, you can also include your 4 digit grid and it will be encoded in one transmission cycle:
You can start your CQ message with one of these formats and it will be sent directed, meaning your callsign will automatically be included. You can also add to the messages without issue:
If you deviate from these formats, you will not be sending a directed message, your grid will not be included, and you must include your callsign in your message.
You can also send CQs on an interval by right clicking the CQ button and selecting a repeat interval. This will cause your station to repeat your CQ transmission until a message is received.
The default way to reply to a cq is with “HW CPY?”. This allows the caller to choose who to connect with and send a signal report to. You can customize this message with a reply, but keep in mind that most stations will be replying with something that can be send in one 15-second transmission. Here’s an example exchange:
TODO
There is an advanced feature for rig control called PTT Command. This allows JS8Call to execute an external script for controlling a rig’s PTT:
What this PTT command does is allow you to execute any command line script to toggle your Rig’s PTT line.
In the above example, the toggle-ptt script will be called with the -p 17 and -s parameters on transmit. The %1 in the above command will be replaced with “on” or “off” depending on the state of the PTT. If you do not add a %1 in your command, “on” and “off” will be appended to the end of the command for invocation.
Example:
If you define your PTT command as: /usr/bin/ptt %1
When JS8Call starts transmitting, it will execute: /usr/bin/ptt “on”
And when JS8Call has finished transmitting, it will execute: /usr/bin/ptt “off”
This is particularly helpful for Raspberry Pi / DRAWS when the GPIO ports are used to control your rig PTT. An example script can be found here: https://gist.github.com/jsherer/dd09895ab23bdf571e2117cdd814c198
When choosing your sound card, you have the option to set individual devices for input and output. You’ll need to find the device that matches what you’ve integrated with your rig. You can choose Mono or Stereo input/output, so try matching those with the capabilities of your device.
For best decoding, when configuring your audio devices you need to apply the right input/output levels:
Audio input it too low! | Audio input is just right! | Audio input is too high! |
TODO
Most operators testing the application can be found +/- 4-8kHz from the standard FT8 frequencies. It is essential to avoid the main FT8 frequencies, as that will cause confusion among WSJT-X operators. Here are some suggested frequencies to use:
You might notice a few of these being close to the JT9 frequencies. Don’t grab your pitchforks! JS8Call blocks out transmitting within the lower 500Hz of the passband. This leaves enough room for 25 simultaneous JT9 signals.
You might also notice that there are a few bands missing from this list. JS8Call does not make a recommendation for calling frequencies on 2200m, 630m, 60m, or higher than 2m, as many of these bands are special cases and have unique rules in many jurisdictions. It’s up to the operator(s) to coordinate and determine the best frequency and operating pattern on these bands.
But also, please keep in mind these are only suggested frequencies. We all have VFOs, so please use them. Just remember to be good operators and prevent from interfering with other signals on our shared bands.
You CAN type in any frequency. JS8Call will not limit which frequencies you can manually transmit on.
You can use the groups.io mailing list to schedule on other frequencies with test operators.
If you want to transmit on a non-standard frequency (recommended) you can either modify the frequencies list in the settings, or you can type directly into the band dropdown box in the top left of the screen.
If you’d like to add custom frequencies for JS8Call, you can do so in the settings:
If you’d like to reset to the suggested frequencies, right click the frequencies box and click Reset.
There are a few quick saved message buttons for transmitting common messages. You can edit these in the settings window. Just be mindful that long messages will take a while to send.
Saved messages have macro-like functionality. These are the macros variables (words that are surrounded by <> characters) that can be used in saved messages which will be replaced when sending the message:
TODO
via https://sourceforge.net/p/wsjt/mailman/message/36224507/
If you’re having trouble, head over to the troubleshooting chatroom for help: https://groups.io/g/JS8Call/chat/1423 or email Jordan directly: kn4crd@gmail.com
JS8Call will not run on my system
Make sure you are running a supported operating system, that you have disabled any programs that may be using your audio device, or preventing JS8Call from using the audio device...like an aggressive antivirus. If you’re running Windows, and have a Windows Defender running, you’ll need to either whitelist JS8Call or turn off the defender.
I see signals on the waterfall but I cannot decode them
Make sure the signals you are seeing are actually JS8Call signals and not FT8 signals (they are incompatible) by ensuring you’re on one of the JS8Call frequencies. Make sure you are in Upper Sideband (USB) mode. Make sure you have synchronized your clock to within 2 seconds of UTC. Make sure you’re not running WSJT-X at the same time.
I do not see any signals on the waterfall
Check your incoming audio from your rig. Make sure JS8Call audio is configured correctly. That means allowing JS8Call to access the “microphone” in the system privacy settings and making sure the levels are set correctly.
Check to make sure you’re on one of the JS8Call frequencies. Keep in mind that JS8Call is still in development and has more than an order of magnitude fewer operators on the air. There may actually be nobody on within your reception range. Check PSKReporter to see if there are others on the band. If you still cannot see any signals, either:
NOTE: Keep in mind that JS8Call isn’t magic...we’re still at the mercy of the ionosphere.
My rig won’t transmit
Check your outgoing audio to your rig. Make sure JS8Call audio is configured correctly. Unplug the rig from the computer and hook up the output to a set of headphones or speakers. Try to transmit, maybe with the TUNE button in the app. Can you hear the tones? If not, then you have an audio problem, if so then you have a transceiver problem. Make sure your PTT is configured correctly for your rig or use VOX. You can test this in the settings. The PTT button will turn green if it can key your transmitter. If you have audio into the rig, but still have no RF out, make sure your rig is configured correctly by checking your digital gain / tx gain / mic levels. After that, make sure your rig works...switch over to FM or CW and send a carrier to make sure the rig can actually transmit at all.
You can send bug reports to Jordan Sherer (KN4CRD) at kn4crd@gmail.com or submit them to the issue tracker here: https://bitbucket.org/widefido/js8call/issues?status=new&status=open
JS8Call uses a JSON API offered over UDP and TCP. More detailed documentation will be available in the future.
JS8Call is under active development and details about the technical implementation are subject to change. Detail will be added here as the implementation stabilizes. Until then, the code is the source of truth for the implementation.
JS8Call uses JS8 modulation as the base transport for data. Being a derivative of WSJT-X, JS8Call heavily leverages the work by the WSJT-X Development Group on the FT8 mode.
Speed | TX Duration | Tones / Symbols | Baud Rate | Tone Spacing / Bandwidth |
SLOW | 25.28 seconds | 8 / 79 | 3.125 baud | 3.125Hz / 25Hz |
NORMAL | 12.64 seconds | 8 / 79 | 6.25 baud | 6.25Hz / 50Hz |
FAST | 7.9 seconds | 8 / 79 | 10 baud | 10Hz / 80Hz |
TURBO | 3.95 seconds | 8 / 79 | 20 baud | 20Hz / 160Hz |
Normal speed is the closest relative to FT8. It uses 3 blocks of 7 tones 7x7 Costas array for synchronization for backwards compatibility.
Fast, Turbo, and Slow speeds use 3 blocks of 7 tones with each block transmitting a unique 7x7 Costas array. This allows for more accurate synchronization.
Based on the modulation bandwidth and error correction, under AWGN with all else being equal:
The JS8Call protocol sits at a layer above the base transport. Much of the implementation is inspired by the design document: https://github.com/jsherer/ft8call with a few deviations from the original proposal.
Messages in JS8Call are transmitted in intervals (frames), with each frame being classified as one of 6 frame types:
Further, each frame includes a transmission flag identifying it as:
And finally, there are special encodings for:
Heartbeat frames are comprised of:
Compound callsign partials are used as one-half of a 2-frame compound transmission when one of the stations includes a compound callsign. Compound callsign partials are always the 1st frame in a 2-frame compound transmission, encoding the “from” portion of a directed command with compound callsigns.
The frame includes:
Compound callsign directed commands are a special case for compound callsign partials where the numeric value encodes a directed command to be used with a compound directed message. It is one-half of a 2-frame compound transmission. Compound callsign directed commands are always the 2nd frame in a 2-frame compound transmission, encoding the “to” portion of a directed command with compound callsigns.
The frame includes:
Standard callsigns can send a directed command in one frame.
The frame includes:
Data frames are the backbone for long-form messages in JS8Call. They are 75-bit frames that use a variable encoding to pack character data into the smallest transmission possible.
Data frames come in two flavors:
Data frames may need to include pad bits because of the variable encoding that character data uses for packing. The variable encoding used is a modified Huffman code that represents the most common characters (based on their frequency of observation in most texts) in fewer bits than less common characters, with the option to shift in alternate alphabets.
The complete modified Huffman code is located in Appendix A. The (s,c)-Dense Code tables include 260K compressible entities.
Callsigns are encoded in 28-bits as described in: EME 2000 - http://www.ka9q.net/papers/eme-2000.ps.gz
Compound callsigns are a 50-bit encoding of 11 characters following the format:
[@A-Z0-9/][A-Z0-9/][A-Z0-9/][/][A-Z0-9/][A-Z0-9/][A-Z0-9/][/][A-Z0-9/][A-Z0-9/][A-Z0-9/]
Since normal callsigns are 28-bits in length, and compound callsigns are 50-bits in length, and the payload size is only 75 bits, there's no way to transmit both in a single frame. So, when addressing a station with a compound call, the transmission is split into two frames, with any directed command included in the extra space of the second frame.
Prefixes and suffixes are 4 character alphanumeric encoded in 21-bits with a 1-bit flag to indicate whether or not it is a prefix or suffix. Alphanumeric digits can each be encoded in 5.25 bits (there are only 1,874,161 combinations of 4 character alphanumeric prefix/suffix, which is less than can be represented in a 21-bit number 221 = 2,097,152)
Grids are encoded in 15-bits as described in: http://physics.princeton.edu/pulsar/k1jt/wsjtx-doc/wsjtx-main-1.7.0.html#PROTOCOL_OVERVIEW
There are many opportunities to explore reliable messaging in the future with the foundation laid, including:
Character code weighted by frequency
" " "01"
"E" "100"
"T" "1101"
"A" "0011"
"O" "11111"
"I" "11100"
"N" "10111"
"S" "10100"
"H" "00011"
"R" "00000"
"D" "111011"
"L" "110011"
"C" "110001"
"U" "101101"
"M" "101011"
"W" "001011"
"F" "001001"
"G" "000101"
"Y" "000011"
"P" "1111011"
"B" "1111001"
"." "1110100"
"V" "1100101"
"K" "1100100"
"-" "1100001"
"+" "1100000"
"?" "1011001"
"!" "1011000"
"\"" "1010101"
"X" "1010100"
"0" "0010101"
"J" "0010100"
"1" "0010001"
"Q" "0010000"
"2" "0001001"
"Z" "0001000"
"3" "0000101"
"5" "0000100"
"4" "11110101"
"9" "11110100"
"8" "11110001"
"6" "11110000"
"7" "11101011"
"/" "11101010"
A whitepaper article is being written on this topic. In the meantime, see jsc.h, jsc.cpp, & jsc_map.cpp in the source repository for the complete dense code table.