# Bodeting, Understanding Bodets Harmony PSA Protocol

## What will you find here?
- Research on how the Bodet Harmony PSA Protocol works
- Checksum Generator for Harmony Packets
- Tools to allow features to be used your Netsilon can't do
- Research on replacing the Bodet Software Called SIGMA and the Time Server for it (I can't even take its name serious) and eventually links to the replacement software called BE-YOUR-OWN-SIGMA (if I achieve reverse engineering it to a certain decentish degree).

## Research folder contains active stuff im working on right now.
If you want to help out with figuring things out this is where to look I'd say

## General info

### Common Hardware Details (Seemingly for all but Master Clock)

- **Platform**: Freescale MQX RTOS
- **MCU**: Some Freescale/NXP Cortex-M4
- **Networking Stack**: LwIP
- **Storage**: MFS-style filesystem, Speakers and Sound Generating Components have an SD Card
- **Web Interface**: Embedded HTTP server (`Server: MQX HTTP - Freescale Embedded Web Server`)
- **Ports & Protocols**:
  - HTTP, FTP (port 21), SNMP, IGMP multicast, UDP
  - FTP Banner: `RTCS FTP Server Ready`

### Build Pipeline

- Project was built using **Windows Jenkins** (who could've guessed that), based on hardcoded paths in strings of firmware files:
`d:\JenkinsJobs\workspace\Indus\Harmonys\Harmonys_trio\Metis_appli\Middlewares\Third_Party\LwIP\`
- Sources show extensive use of LwIP stack and standard Freescale directory structures

---

### Possible Default Credentials

Based on repeated appearances in both firmware strings :

| Username | Password             |
|----------|----------------------|
| `public` | `jkl1vi5erjnfh`      |
| `public` | `aSe2=9Z8gOi37*`     |

PS: Not tested extensively

## IP Button Packet Anatomy

Each IP Button Bodet Sound Protocol Payload follows a consistent format:

```
[MEL HEADER]-[LENGTH]-[START]-[SEQUENCE]-[COMMAND]-[ZONE INFO]-[METADATA]-[CHECKSUM]
```

Seems to send two of the packets each time a button is pressed

### MEL Header

* Hex: `4D 45 4C`
* ASCII: "MEL" (probably short for "Melody")
* Identifies this as a Bodet Sound Protocol packet

### Length

* 2 bytes
* Indicates payload size in decimal (excluding MAC/IP/UDP headers)
* Example: `0021` = 33 bytes

### Start Marker

* Constant: `0100`
* Marks start of command block

### Sequence Number

* 2 bytes, Little Endian
* Only the **first byte** appears to increment; the second is just `FF`, suggesting padding or reserved space

### Command Code

* Examples:

  * `3001` = Melody
  * `5001` = Alarm
  * `5002` = Stop

### Zone Info

* 12 bytes (6 words of 16 bits = 96 bits)
* Represents **zones 1–100** using a bitfield
* Each zone bit is encoded as:

  ```
  byte_index = (zone - 1) // 8
  bit_index = (zone - 1) % 8
  set bit (7 - bit_index) in byte[byte_index]
  ```
* You can enable **multiple zones** in a single packet by OR-ing the relevant bits
* Examples:

  * `8000 0000 0000 0000 0000 0000` = Zone 8 only
  * `0000 8000 0000 0000 0000 0000` = Zone 16 only
  * `0000 0000 0000 0000 0020 0000` = Zone 86

- Note : this is just an assumption not enough testing has been done

### Metadata Fields

* After Zone Info:

  * `0001` - Probably Fixed field (sometimes 0002 with certain multizone commands)
  * `03` - Volume (1-8)
  * `02` - Repeat count (or `00` for infinite)
  * `01  - Probably Fixed field or field to actually tell the device yes play something lol
  * `09` - Melody ID (9 in this case)
  * `0100` - **end-of-command marker**, appears to terminate command blocks (expept for stop commands)

### Checksum (2 bytes)

* **Position:** Final two bytes of packet
* **Algorithm:** PSA Checksum algorithm
* **Implementation:** See the Checksum Implementation section below
* (Looks often like this `014a`)

---

## Examples (Annotated)

### Melody to Zone 8, Melody 9, Infinite Repeats

```
4d454c 0021 0100 28ff 3001 8000 0000 0000 0000 0000 0000 0001 03 00 01 09 0100 01 d5
```

* Zone 8 = `8000 ...`
* Volume = `03`, Repeats = `00` (infinite)
* Melody = `09`
* Checksum = `D5`

### Stop All Zones

```
4d454c 001a 0100 24ff 5002 ffff ffff ffff ffff ffff ffff 0f 0107
```

* All zones = `FF FF ...` (you actually cant choose which zone to turn of system refuses zonemaps here)
* Command = Stop (`5002`)
* Ends with `0F 01` instead of `0100` → supports theory that `0100` indicates only the end of melody/alarm command block
* Checksum = `0107`

---

## Checksum Implementation

The checksum algorithm used by Bodet PSA protocol has been successfully reverse engineered thanks to severe insanity (I didn't realize it as 2 bytes until I already wasted 5 days reverse engineering it). It works as follows btw:

```python
def compute_psa_checksum(data: bytes) -> bytes:
    var_e = 0x0000  # Starting seed value
    for i in range(len(data)):
        var_e ^= (data[i] + i) & 0xFFFF
    return var_e.to_bytes(2, 'big')  # 2-byte checksum, big-endian
```
PS: I extracted this info by decompiling the SIGMA Software Package by Bodet

Key characteristics:
- Uses a seed value of 0x0000
- For each byte in the data:
  - Adds the byte value and its index
  - XORs the result with the running checksum
  - Applies a 16-bit mask (0xFFFF)
- Returns a 2-byte big-endian checksum

This algorithm allows for generating valid packets for the Bodet PSA system. It was verified against known working packets and matches the behavior observed in the system.

To use this algorithm:
1. Prepare your packet data excluding the checksum
2. Calculate the checksum using the function above or the python code in this repo.
3. Append the 2-byte checksum to your packet data
4. Send to your Bodet Harmony Multicast Address (Port 1681)

For a ready-to-use implementation, see the `hex_checksum.py` script in this repository.

---
##


## Reminence of the Journey here.

The `executables/hexen.py` script is not recommended, I used it to make some sample data by listening if the Harmony Speaker would produce noises. It is filled with cursewords

