Skip to content

Commit

Permalink
Merge pull request #79 from OpenVoiceOS/feat/support_mark1
Browse files Browse the repository at this point in the history
Add support for Mycroft Mark 1 device
  • Loading branch information
goldyfruit authored May 3, 2024
2 parents f122f11 + 0f4ca36 commit f1e038b
Show file tree
Hide file tree
Showing 19 changed files with 280 additions and 6 deletions.
11 changes: 11 additions & 0 deletions ansible/roles/ovos_hardware_mark1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# ovos_hardware_mark1

Setup the atmega328p Arduino chip running on the Mark 1 device.

## License

Apache 2

## Author Information

Gaëtan Trellu - @goldyfruit
1 change: 1 addition & 0 deletions ansible/roles/ovos_hardware_mark1/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
---
39 changes: 39 additions & 0 deletions ansible/roles/ovos_hardware_mark1/files/initialize.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/env bash
#
# This script initialiaze the atmega328p chip from the Mark 1 device.
# Once initialized the eyes color will be changed to yellow and
# the mouth text will display "booting".
# As final action, if the sndrpiproto soundcard is detected then
# it will be configured.

# Variables
eyes_color="16760576"
mouth_text="booting"
tty_device=/dev/ttyAMA0
alsa_card="sndrpiproto"
alsa_configured=/opt/mark1/alsa.configured

# Initialiaze the firmware and wait two seconds
avrdude -p atmega328p -c linuxgpio -U signature:r:-:i -F
sleep 2

# Set eyes color
echo "eyes.color=$eyes_color" > "$tty_device"

# Set mouth text
echo "mouth.text=$mouth_text" > "$tty_device"

# Set default values to sndrpiproto ALSA card
if grep "$alsa_card" /proc/asound/cards -q; then
# Set volume mixer only once
if [ ! -f "$alsa_configured" ]; then
amixer -c "$alsa_card" cset numid=1 100,100
touch "$alsa_configured"
fi
amixer -c "$alsa_card" cset numid=2 on
amixer -c "$alsa_card" cset numid=6 on
amixer -c "$alsa_card" cset numid=10 on
amixer -c "$alsa_card" cset numid=14 1
amixer -c "$alsa_card" cset numid=13 on
amixer -c "$alsa_card" cset numid=9 on
fi
11 changes: 11 additions & 0 deletions ansible/roles/ovos_hardware_mark1/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
- name: Reload Systemd User
become: true
become_user: "{{ ovos_installer_user }}"
ansible.builtin.systemd_service:
daemon_reload: true
scope: user

- name: Set Reboot
ansible.builtin.set_fact:
ovos_installer_reboot: true
28 changes: 28 additions & 0 deletions ansible/roles/ovos_hardware_mark1/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
galaxy_info:
author: Gaëtan trellu (@goldyfruit)
description: Open Voice OS installer Mark 1
company: Smart'Gic
standalone: true

issue_tracker_url: https://github.com/openvoiceos/ovos-installer/issues

license: Apache-2.0

min_ansible_version: "2.12"

platforms:
- name: Debian
versions:
- bookworm
- bullseye

galaxy_tags:
- openvoiceos
- ovos
- hivemind
- voiceassistant
- mark1
- atmega328p

dependencies: []
35 changes: 35 additions & 0 deletions ansible/roles/ovos_hardware_mark1/tasks/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
- name: Check for /boot/firmware directory
ansible.builtin.stat:
path: /boot/firmware
register: _boot_config_status

- name: Set _boot_directory fact
ansible.builtin.set_fact:
_boot_directory: "{{ '/boot/firmware' if _boot_config_status.stat.exists | bool else '/boot' }}"

- name: Manage TTY and soundcard overlays
ansible.builtin.lineinfile:
path: /boot/firmware/config.txt
regexp: "^{{ item }}"
line: "{{ item }}"
notify: Set Reboot
loop:
- dtoverlay=miniuart-bt
- dtoverlay=proto-codec

- name: Disable snd_bcm2835 audio interface
ansible.builtin.lineinfile:
path: "{{ _boot_directory }}/config.txt"
regexp: "^{{ item.key }}="
line: "{{ item.key }}={{ item.value }}"
notify: Set Reboot
loop:
- { key: "dtparam=audio", value: "off" }

- name: Redirect console to tty1 only
ansible.builtin.replace:
path: "{{ _boot_directory }}/cmdline.txt"
regexp: '\bconsole=serial0,115200\b\s?'
replace: ""
notify: Set Reboot
9 changes: 9 additions & 0 deletions ansible/roles/ovos_hardware_mark1/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
- name: Include prepare.yml
ansible.builtin.import_tasks: prepare.yml

- name: Include config.yml
ansible.builtin.import_tasks: config.yml

- name: Include service.yml
ansible.builtin.import_tasks: service.yml
25 changes: 25 additions & 0 deletions ansible/roles/ovos_hardware_mark1/tasks/prepare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
- name: Add {{ ovos_installer_user }} to dialout group
ansible.builtin.user:
name: "{{ ovos_installer_user }}"
groups: dialout
append: true

- name: Create directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ ovos_installer_user }}"
group: "{{ ovos_installer_user }}"
mode: "0755"
loop:
- "{{ ovos_installer_user_home }}/.config/systemd/user"
- "{{ _ovos_hardware_mark1_workind_directory }}"

- name: Configure initialize.sh to {{ _ovos_hardware_mark1_workind_directory }}
ansible.builtin.copy:
src: initialize.sh
dest: "{{ _ovos_hardware_mark1_workind_directory }}/initialize.sh"
owner: "{{ ovos_installer_user }}"
group: "{{ ovos_installer_user }}"
mode: "0755"
21 changes: 21 additions & 0 deletions ansible/roles/ovos_hardware_mark1/tasks/service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
- name: Copy mark1 systemd unit file
ansible.builtin.template:
src: mark1.service.j2
dest: "{{ ovos_installer_user_home }}/.config/systemd/user/mark1.service"
owner: "{{ ovos_installer_user }}"
group: "{{ ovos_installer_user }}"
mode: "0644"
notify: Reload Systemd User

- name: Flush handlers service
ansible.builtin.meta: flush_handlers

- name: Enable mark1 systemd unit
become: true
become_user: "{{ ovos_installer_user }}"
ansible.builtin.systemd_service:
name: mark1.service
enabled: true
force: true
scope: user
15 changes: 15 additions & 0 deletions ansible/roles/ovos_hardware_mark1/templates/mark1.service.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Documentation=https://github.com/MycroftAI/enclosure-mark1
Description=Mycroft Mark 1's atmega328p initialization
After=network-online.target
ConditionPathExists=/dev/ttyAMA0

[Service]
Type=oneshot
ExecStart=/opt/mark1/initialize.sh
Restart=on-failure
RestartSec=5s
RemainAfterExit=yes

[Install]
WantedBy=default.target
3 changes: 3 additions & 0 deletions ansible/roles/ovos_hardware_mark1/vars/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
_ovos_hardware_mark1_avrdude_binary: /usr/local/bin/avrdude
_ovos_hardware_mark1_workind_directory: /opt/mark1
4 changes: 2 additions & 2 deletions ansible/roles/ovos_hardware_mark2/tasks/vocalfusion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
force: true
scope: user

- name: Delete /usr/src/vocalfusion once compiled
- name: Delete {{ _ovos_hardware_mark2_vocalfusion_src_path }} once compiled
ansible.builtin.file:
path: /usr/src/vocalfusion
path: "{{ _ovos_hardware_mark2_vocalfusion_src_path }}"
state: absent
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ git+https://github.com/OpenVoiceOS/ovos-ocp-youtube-plugin.git
{% if 'tas5806' in ovos_installer_i2c_devices %}
git+https://github.com/OpenVoiceOS/ovos-PHAL-plugin-hotkeys.git
{% endif %}
{% if 'atmega328p' in ovos_installer_i2c_devices %}
git+https://github.com/OpenVoiceOS/ovos-PHAL-plugin-mk1.git
{% endif %}
git+https://github.com/OpenVoiceOS/ovos-stt-plugin-chromium.git
git+https://github.com/OpenVoiceOS/ovos-tts-plugin-polly.git
git+https://github.com/OpenVoiceOS/ovos-utterance-corrections-plugin.git
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ poorman-handshake
# No PyPi release
git+https://github.com/JarbasHiveMind/HiveMind-voice-sat.git
git+https://github.com/JarbasHiveMind/hivemind_websocket_client.git
{% if 'tas5806' in ovos_installer_i2c_devices %}
git+https://github.com/OpenVoiceOS/ovos-PHAL-plugin-hotkeys.git
{% endif %}
{% if 'atmega328p' in ovos_installer_i2c_devices %}
git+https://github.com/OpenVoiceOS/ovos-PHAL-plugin-mk1.git
{% endif %}
git+https://github.com/OpenVoiceOS/ovos-stt-plugin-chromium.git
git+https://github.com/OpenVoiceOS/ovos-tts-plugin-polly.git
{% if ovos_installer_cpu_is_capable | bool %}
Expand Down
8 changes: 8 additions & 0 deletions ansible/site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@
- always

roles:
- role: ovos_hardware_mark1
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version is version('11', '>=')
- "'atmega328p' in ovos_installer_i2c_devices"
- ansible_architecture == "aarch64"

- role: ovos_hardware_mark2
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version is version('11', '>=')
- "'Raspberry Pi 4' in ovos_installer_raspberrypi or 'Raspberry Pi 5' in ovos_installer_raspberrypi"
- "'tas5806' in ovos_installer_i2c_devices"
- ansible_architecture == "aarch64"

- role: ovos_installer

tasks:
Expand Down
3 changes: 3 additions & 0 deletions tui/detection.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ for device in "${DETECTED_DEVICES[@]}"; do
tas5806)
HARDWARE_DETECTED="Mycroft Mark II"
;;
atmega328p)
HARDWARE_DETECTED="Mycroft Mark 1"
;;
esac
done
export HARDWARE_DETECTED
Expand Down
5 changes: 3 additions & 2 deletions tui/methods.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ available_methods=(containers virtualenv)

# When 32-bit CPU is detected, the only method available
# will be Python virtualenv as there are no 32-bit container
# images available.
if [[ "$ARCH" != @(x86_64|aarch64) ]]; then
# images available. Same for Raspberry Pi 3 as containers
# might be too heavy for this board.
if [[ "$ARCH" != @(x86_64|aarch64) ]] && [[ "$RASPBERRYPI_MODEL" == *"Raspberry Pi 3"* ]]; then
active_method="virtualenv"
available_methods=(virtualenv)
fi
Expand Down
53 changes: 51 additions & 2 deletions utils/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ function ver() {
# This function takes an argument like "2f", this will be converted
# to "0x2f".
function i2c_get() {
if i2cdetect -y -a "$I2C_BUS" "0x$1" "0x$1" 2>>"$LOG_FILE" | grep -q "$1"; then
if i2cdetect -y -a "$I2C_BUS" "0x$1" "0x$1" 2>>"$LOG_FILE" | grep -Eq "$1|UU"; then
return 0
fi
return 1
Expand All @@ -380,9 +380,58 @@ function i2c_scan() {
for device in "${!SUPPORTED_DEVICES[@]}"; do
address="${SUPPORTED_DEVICES[$device]}"
if i2c_get "$address"; then
DETECTED_DEVICES+=("$device")
if [ "$device" == "atmega328p" ]; then
detect_mark1_device
else
DETECTED_DEVICES+=("$device")
fi
fi
done
echo -e "[$done_format]"
fi
}

# Downloads avrdude binary with libgpiod support from
# https://artifacts.smartgic.io. Once downloaded, a custom avrduderc will
# be created with the Mark 1 required pinout. This binary will only be
# downloaded when I2C 1a address (UU reserved address) and Raspberry Pi
# board are detected.
function setup_avrdude() {
if [ -f "$AVRDUDE_BINARY_PATH" ]; then
rm "$AVRDUDE_BINARY_PATH"
fi

curl -s -f -L "$AVRDUDE_BINARY_URL" -o "$AVRDUDE_BINARY_PATH" &>>"$LOG_FILE"
chmod 0755 "$AVRDUDE_BINARY_PATH" &>>"$LOG_FILE"

cat <<EOF >"$RUN_AS_HOME/.avrduderc"
# Mark 1 pinout
programmer
id = "linuxgpio";
desc = "Use the Linux sysfs interface to bitbang GPIO lines";
type = "linuxgpio";
connection_type = linuxgpio;
prog_modes = PM_ISP;
reset = 22;
sck = 27;
sdo = 24;
sdi = 17;
;
EOF
chown "$RUN_AS:$RUN_AS" "$RUN_AS_HOME/.avrduderc" &>>"$LOG_FILE"
curl -s -f -L "$AVRDUDE_CONFIG_URL" -o "$AVRDUDE_CONFIG_PATH" &>>"$LOG_FILE"
}

# This function retrieves the atmega328p signature when present. If the
# signature matches a specific value then it means that a Mark 1 device
# is detected.
# This function is only triggered when a I2C reserved device is detected.
function detect_mark1_device() {
setup_avrdude
atmega328p="$(avrdude -C +"$RUN_AS_HOME"/.avrduderc -p atmega328p -c linuxgpio -U signature:r:-:i -F 2>>"$LOG_FILE" | head -1)"
if [ "$atmega328p" == "$ATMEGA328P_SIGNATURE" ] ; then
DETECTED_DEVICES+=("atmega328p")
return 0
fi
return 1
}
6 changes: 6 additions & 0 deletions utils/constants.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/bin/env bash

export ATMEGA328P_SIGNATURE=":030000001E950F3B"
export AVRDUDE_BINARY_PATH=/usr/local/bin/avrdude
export AVRDUDE_BINARY_URL="https://artifacts.smartgic.io/avrdude/avrdude-aarch64"
export AVRDUDE_CONFIG_PATH=/usr/local/etc/avrdude.conf
export AVRDUDE_CONFIG_URL="https://artifacts.smartgic.io/avrdude/avrdude.conf"
declare -a DETECTED_DEVICES
export DETECTED_DEVICES
export DT_FILE=/sys/firmware/devicetree/base/model
Expand Down Expand Up @@ -45,6 +50,7 @@ export SCENARIO_NAME="scenario.yaml"
export SCENARIO_PATH=""
declare -rA SUPPORTED_DEVICES=(
["tas5806"]="2f" #https://www.ti.com/product/TAS5806MD
["atmega328p"]="1a" #https://www.microchip.com/en-us/product/atmega328p
)
export SUPPORTED_DEVICES
export TUI_WINDOW_HEIGHT="35"
Expand Down

0 comments on commit f1e038b

Please sign in to comment.