# Humpback DDS

RF signal generator using Urukul, Humpback and STM32 NUCLEO-H743ZI2

## Nix commands

Start nix shell before anything.
```shell
nix-shell
```

Flash firmware onto STM32 NUCLEO-H743ZI2 using OpenOCD.
```shell
openocd -f openocd/openocd.cfg -f openocd/main.cfg
```

Alternatively, an equivalent Nix command can also do the work
```shell
openocd-flash main
```

## Networking Setup
At the moment, both IP addresses of the STM32 board and MQTT broker are hardcoded.
MAC address of the STM32 board is also hardcoded.

### STM32 IP Address
IP address is hardcoded in the file `src/main.rs`, line 171.
```rust
store.ip_addrs[0] = net::wire::IpCidr::new(net::wire::IpAddress::v4(192, 168, 1, 200), 24);
```
The IP address shown above corresponds to `192.168.1.200`, in a `/24` address block.
Modify this line to the change the IP address of STM32 board.

### STM32 MAC Address
IP address is hardcoded in the file `src/main.rs`, line 156.
```rust
let mac_addr = net::wire::EthernetAddress([0xAC, 0x6F, 0x7A, 0xDE, 0xD6, 0xC8]);
```
The MAC address shown above corresponds to `AC::6F::7A::DE::D6::C8`.
Modify this line to the change the MAC address of STM32 board.

### Broker IP Address
IP address is hardcoded in the file `src/main.rs`, line 241.
```rust
    IpAddr::V4(Ipv4Addr::new(192, 168, 1, 125)),
```
This program will try attempt to connect to `192.168.1.125:1883`.
Modify this line to the change the IP address of MQTT broker.
Note that the broker must accept TCP connection at `port 1883`.

## MQTT Broker
Mosquitto is within the Nix package.
Starting a Mosquitto MQTT broker can be as simple as the following line.
```shell
mosquitto
```
The MQTT broker will be started locally, at port 1883.

To enable feedback from the device, subscribe to all subtopics under `Urukul/Feedback` on a separate terminal.
```shell
mosquitto_sub -h <broker ip address> -t Urukul/Feedback/#
```
Note that subscription to the feedback topic is completely optional.


## Publishing MQTT messages through Mosquitto
Controlling Humpback-DDS can be achieved by sending specific MQTT commands through Mosquitto. The device will listen to all publishes that are under the `Urukul/Control` or `/Urukul/Control` topic. A MQTT message can be published by the following command.
```shell
mosquitto_pub -h <broker ip address> -t <topic> -m <message>
```
For example, to publish a local MQTT broker, with the topic of `Foo/Bar` and `Baz` as the message, enter this command.
```shell
mosquitto_pub -h localhost -t Foo/Bar -m "Baz"
```
Note that MQTT topics are case-sensitive.  
Alternatively, the following nix command provided by the shell simplify the syntax.
```shell
publish-mqtt <topic> <message>
```
This will send the MQTT message to a local MQTT broker at port 1883, with specified topic and message. The example above can be simplified into:
```shell
publish-mqtt Foo/Bar "baz"
```

## List of Commands
All currently supported commands are listed below.  
**Note: The following table only lists the subtopic. To make a full topic, add `Urukul/Control/` in front of all subtopics.**  
### Example: Full topic of Reset command
```shell
Urukul/Control/Reset
```

| Subtopic                                | Message                                                            | Functionality|
| --------------------------------------- | ------------------------------------------------------------------ | ---|
| `Reset`                                 |                                                                    | Reset the device|
| `ChannelX/Switch`                       | `<off/on>`                                                         | Turn off/on the RF switch at channel X.|
| `ChannelX/Attenuation`                  | `<atten> [dB]`                                                     | Set attenuation of channel X.|
| `Clock/Source`                          | `<clk_src>`                                                        | Select the clock source of Urukul.|
| `Clock/Frequency`                       | `<f_clk> [unit]`                                                   | Set the clock frequency of the clock source of Urukul.|
| `Clock/Source`                          | `<clk_div>`                                                        | Set the clock division of Urukul.|
| `Clock`                                 | `frequency: <f_clk> [unit], source: <clk_src>, division: <clk_div>`| Setup the clock tree for Urukul.|
| `ChannelX/SystemClock`                  | `<f_sys_clk> [unit]`                                               | Set the system clock frequency of channel X.|
| `ChannelX/ProfileY/Singletone/Frequency`| `<freq> [unit]`                                                    | Setup a single tone profile at channel X, profile Y, with frequency `<freq> [unit]`.|
| `ChannelX/ProfileY/Singletone/Amplitude`| `<ampl>`                                                           | Setup a single tone profile at channel X, profile Y, with amplitude factor `<ampl>`.|
| `ChannelX/ProfileY/Singletone/Phase`    | `<phase> [deg]`                                                    | Setup a single tone profile at channel X, profile Y, with phase `<phase> [deg]`.|
| `ChannelX/ProfileY/Singletone`          | `frequency: <freq> [unit], amplitude: <ampl>, phase: <phase>`      | Setup a compelte single tone profile at channel X, profile Y.|
| `Profile`                               | `<pr_num>`                                                         | Switch to a DDS profile across all channels.|

## Reset the device
- Topic: `Urukul/Control/Reset`
- Message: (Don't care)

The `Reset` command resets the device. The effects are:
- Turn off all RF switches.
- Set attenuations to be 31.5 dB for all attenuators.
- Set Urukul clock source to be the internal oscillator, with 100MHz.
- Set Urukul clock divider to 4.
- Reset all 4 DDS chips.
### Example
```shell
publish-mqtt Urukul/Control/Reset
```
This resets the device.

## RF Switch
- Topic: `Urukul/Control/Channel<ch_num>/Switch`
  - ch_num: The channel number, from 0 to 3.
- Message: `<off/on>`

This command turns off/on an RF switch of a channel.
### Example
```shell
publish-mqtt Urukul/Control/Channel0/Switch "on"
```
This turns on the channel 0 RF switch.

## Attenuator
- Topic: `Urukul/Control/Channel<ch_num>/Attenuator`
  - ch_num: The channel number, from 0 to 3.
- Message: `<atten> [dB]`
  - atten: Attenuation of the attenuator of the specified channel. The unit dB is optional. Valid attenuation is within [0, 31.5] (inclusive) in decibel.

### Example
```shell
publish-mqtt Urukul/Control/Channel0/Attenuator "20 dB"
```
This sets the attenuation of the channel 0 attenuator to be 20 dB.

## Urukul Clock Tree
1. Clock Frequency
   - Topic: `Urukul/Control/Clock/Frequency`
   - Message: `<f_clk> [unit]`
     - f_clk: Clock frequency of the Urukul clock source.
     - unit: **(Optional)** Unit of f_clk, supports `Hz`, `kHz`, `MHz`, `GHz`. `Hz` if unspecified.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Clock/Frequency "100 MHz"
   ```
   This sets the clock frequency of Urukul to be 100 MHz.

2. Clock Source
   - Topic: `Urukul/Control/Clock/Source`
   - Message: `<clk_src>`
     - clk_src: Clock source of Urukul. It can only be `OSC`, `MMCX` and `SMA`.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Clock/Source "OSC"
   ```
   This sets the clock source of Urukul to be the internal oscillator.  
   (Note: The internal oscillator should have a frequency of 100MHz, though this command does not setup the clock frequency.)

3. Clock Frequency Division
   - Topic: `Urukul/Control/Clock/Division`
   - Message: `<clk_div>`
     - clk_div: Clock frequency division of Urukul. It can only be 1, 2, or 4.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Clock/Division "4"
   ```
   This divides the clock frequency of Urukul by a factor of 4.

4. Clock Overall Setup
   - Topic: `Urukul/Control/Clock`
   - Message: `frequency: <f_clk> [unit], source: <clk_src>, division: <clk_div>`
     - f_clk, unit, clk_src, clk_div: Same as above.
     - Argument can be permutated.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Clock "source: OSC, frequency: 100 MHz, division: 4"
   ```
   This is identical to the 3 examples above.

## DDS System Clock Frequency
- Topic: `Channel<ch_num>/SystemClock`
- Message: `<f_sys_clk> [unit]`
  - f_sys_clk: DDS System Clock frequency a channel.
  - unit: **(Optional)** Unit of f_clk, supports `Hz`, `kHz`, `MHz`, `GHz`. `Hz` if unspecified.
### Example
```shell
publish-mqtt Urukul/Control/Chammel1/SystemClock "1 GHz"
```
This sets the system clock frequency of channel 1 to 1 GHz.

## Single Tone Profile
1. Single Tone Frequency
   - Topic: `Urukul/Control/Channel<ch_num>/Profile<pr_num>/Singletone/Frequency`
     - ch_num: Channel number.
     - pr_num: Profile number.
   - Message: `<freq> [unit]`
     - freq: Output frequency of the DDS single tone profile.
     - unit: **(Optional)** Unit of freq, supports `Hz`, `kHz`, `MHz`, `GHz`. `Hz` if unspecified.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Channel1/Profile2/Singletone/Frequency "3 MHz"
   ```
   This sets the output frequency of the single tone profile at channel 1, profile 2 to be 3 MHz.

2. Single Tone Amplitude
   - Topic: `Urukul/Control/Channel<ch_num>/Profile<pr_num>/Singletone/Amplitude`
     - ch_num: Channel number.
     - pr_num: Profile number.
   - Message: `<ampl>`
     - ampl: Amplitude factor of the single tone profile. It ranges from 0 to 1 inclusive.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Channel1/Profile2/Singletone/Amplitude "0.5"
   ```
   This sets the output amplitude factor of the single tone profile at channel 1, profile 2 to be 0.5.

3. Single Tone Phase
   - Topic: `Urukul/Control/Channel<ch_num>/Profile<pr_num>/Singletone/Phase`
     - ch_num: Channel number.
     - pr_num: Profile number.
   - Message: `<phase>`
     - phase: Phase of the single tone profile. The unit is in degree.
     - deg: **Optional** Specifies the unit of phase to be degree.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Channel1/Profile2/Singletone/Degree "0.0 deg"
   ```
   This sets the phase of the single tone profile at channel 1, profile 2 to be 0 degree.

4. Single Tone Overall Setup
   - Topic: `Urukul/Control/Channel<ch_num>/Profile<pr_num>/Singletone`
   - Message: `frequency: <freq> [unit], amplitude: <ampl>, phase: <phase>`
     - All parameters are the same as above commands.
     - Argument can be permutated.
   ### Example
   ```shell
   publish-mqtt Urukul/Control/Clock "frequency: 3 MHz, phase: 0.0 deg, amplitude: 0.5"
   ```
   This is identical to the 3 examples above.

## Switching DDS Profile
- Topic: `Urukul/Control/Profile`
- Message: `<profile>`
### Example
```shell
publish-mqtt Urukul/Control/Profile "5"
```
This is selects profile 5 for all DDS channels.