├── eepromutils
├── voicehat.eep
├── Makefile
├── README.txt
├── eeptypes.h
├── eeprom_settings.txt
├── eepflash.sh
├── eepdump.c
└── eepmake.c
├── Rpi-custom-voice-hat-wiring.fzz
├── Rpi-custom-voice-hat-wiring.png
├── README.md
├── audio-config
└── scripts
│ ├── asound.conf
│ ├── custom-voice-hat.sh
│ └── install-i2s.sh
└── Instructions.txt
/eepromutils/voicehat.eep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shivasiddharth/custom-voice-hat/master/eepromutils/voicehat.eep
--------------------------------------------------------------------------------
/Rpi-custom-voice-hat-wiring.fzz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shivasiddharth/custom-voice-hat/master/Rpi-custom-voice-hat-wiring.fzz
--------------------------------------------------------------------------------
/Rpi-custom-voice-hat-wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shivasiddharth/custom-voice-hat/master/Rpi-custom-voice-hat-wiring.png
--------------------------------------------------------------------------------
/eepromutils/Makefile:
--------------------------------------------------------------------------------
1 | # Current tools are eepmake and eepdump
2 |
3 | CC ?= gcc
4 |
5 | all: eepmake eepdump
6 |
7 | eepmake: eeptypes.h eepmake.c
8 | $(CC) eepmake.c -o eepmake -Wno-format
9 |
10 | eepdump: eeptypes.h eepdump.c
11 | $(CC) eepdump.c -o eepdump -Wno-format
12 |
13 | clean:
14 | rm -f eepmake eepdump
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # custom-voice-hat
2 | Create a custom Voice HAT, much like Google's VOICE HAT
3 |
4 | Use the below video for reference.
5 |
6 |
9 |
--------------------------------------------------------------------------------
/eepromutils/README.txt:
--------------------------------------------------------------------------------
1 | Utilities to create, flash and dump HAT EEPROM images.
2 |
3 | Edit eeprom_setting.txt for your particular board and run through
4 | eepmake tool, then use eepflash tool to write to attached HAT ID EEPROM
5 |
6 | Tools available:
7 |
8 | eepmake: Parses EEPROM text file and creates binary .eep file
9 |
10 | eepdump: Dumps a binary .eep file as human readable text (for debug)
11 |
12 | eepflash: Write or read .eep binary image to/from HAT EEPROM
13 |
--------------------------------------------------------------------------------
/audio-config/scripts/asound.conf:
--------------------------------------------------------------------------------
1 | options snd_rpi_googlemihat_soundcard index=0
2 |
3 | pcm.softvol {
4 | type softvol
5 | slave.pcm dmix
6 | control {
7 | name Master
8 | card 0
9 | }
10 | }
11 |
12 | pcm.micboost {
13 | type plug
14 | slave.pcm dsnoop
15 |
16 | }
17 |
18 | pcm.!default {
19 | type asym
20 | playback.pcm "plug:softvol"
21 | capture.pcm "plug:micboost"
22 | }
23 |
24 | ctl.!default {
25 | type hw
26 | card 0
27 | }
28 |
--------------------------------------------------------------------------------
/audio-config/scripts/custom-voice-hat.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Configure Raspberry Pi audio for Custom Voice HAT.
4 |
5 | set -o errexit
6 |
7 | if [[ $EUID -ne 0 ]]; then
8 | echo "This script must be run as root (use sudo)" 1>&2
9 | exit 1
10 | fi
11 |
12 | cd "$(dirname "${BASH_SOURCE[0]}")/.."
13 |
14 | asoundrc=/home/pi/.asoundrc
15 | global_asoundrc=/etc/asound.conf
16 |
17 | for rcfile in "$asoundrc" "$global_asoundrc"; do
18 | if [[ -f "$rcfile" ]] ; then
19 | echo "Renaming $rcfile to $rcfile.bak..."
20 | sudo mv "$rcfile" "$rcfile.bak"
21 | fi
22 | done
23 |
24 | sudo cp scripts/asound.conf "$global_asoundrc"
25 | echo "Installing CUSTOM Voice HAT config at $global_asoundrc"
26 |
--------------------------------------------------------------------------------
/audio-config/scripts/install-i2s.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2017 Google Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o errexit
18 |
19 | if [[ $EUID -ne 0 ]]; then
20 | echo "This script must be run as root (use sudo)" 1>&2
21 | exit 1
22 | fi
23 |
24 | set -e
25 |
26 | sed -i \
27 | -e "s/^dtparam=audio=on/#\0/" \
28 | -e "s/^#\(dtparam=i2s=on\)/\1/" \
29 | /boot/config.txt
30 | grep -q "dtoverlay=i2s-mmap" /boot/config.txt || \
31 | echo "dtoverlay=i2s-mmap" >> /boot/config.txt
32 | grep -q "dtoverlay=googlevoicehat-soundcard" /boot/config.txt || \
33 | echo "dtoverlay=googlevoicehat-soundcard" >> /boot/config.txt
34 | grep -q "dtparam=i2s=on" /boot/config.txt || \
35 | echo "dtparam=i2s=on" >> /boot/config.txt
36 |
37 |
--------------------------------------------------------------------------------
/Instructions.txt:
--------------------------------------------------------------------------------
1 | # Parts List
2 | 1. Adafruit I2S MEMS Microphone Breakout - SPH0645LM4H - 2Nos - https://www.adafruit.com/product/3421
3 | 2. Adafruit I2S 3W Class D Amplifier Breakout - MAX98357A - 1No - https://www.adafruit.com/product/3006
4 | 3. Adafruit Perma-Proto HAT for Pi Mini Kit - With EEPROM - 1No - https://www.adafruit.com/product/2314
5 |
6 | # Following steps to be completed on the Pi.
7 |
8 | #Clone the project onto the pi
9 | git clone https://github.com/shivasiddharth/custom-voice-hat
10 |
11 | 1. Turn on i2s support in /boot/config.txt with:
12 | sudo nano /boot/config.txt
13 |
14 | ****Uncomment the following****
15 | #dtparam=i2s=on
16 | #dtparam=i2c_arm=on
17 | #dtparam=spi=on
18 | #dtparam=audio=on
19 |
20 | ****Add the following new entry****
21 | dtparam=i2c_vc=on
22 |
23 | Save Exit and Reboot.
24 |
25 | 2. Check for the Hats folder:
26 | cd /proc/device-tree/
27 |
28 | 3. Open a new terminal and change directory to eepromutils:
29 | cd /home/pi/custom-voice-hat/eepromutils
30 |
31 | 4. Make the EEPROM flasher executable and Flash the EEPROM with the eeprom file:
32 | sudo chmod +x ./eepflash.sh
33 | sudo ./eepflash.sh -w -f=voicehat.eep -t=24c32
34 |
35 | 5. Update raspberry pi kernels:
36 | sudo apt-get update
37 | sudo apt-get install raspberrypi-kernel
38 |
39 | 6. Reboot
40 | sudo reboot
41 |
42 | 7. Check if your HAT is recognized,:
43 | cd /proc/device-tree/
44 |
45 | ***YOU WILL HAVE A HAT FOLDER NOW WITH VOICE HAT DETAILS***
46 |
47 | # Shutdown and Wire the Parts as indicated in the attached wiring diagram
48 | ***CAUTION- Amplifier board should be powered using 5V and the Mics using 3.3v***
49 |
50 | # Start your Pi and move into the audio configuration scripts:
51 | cd /home/pi/custom-voice-hat/audio-config/scripts/
52 |
53 | #Make the scripts executable:
54 | sudo chmod +x ./custom-voice-hat.sh
55 | sudo chmod +x ./install-i2s.sh
56 |
57 | #Run the Executable scripts
58 | sudo ./custom-voice-hat.sh
59 | sudo ./install-i2s.sh
60 |
61 | ****RUN THE custom-voice-hat.sh script untill you get .bak notification****
62 | ****REBOOT and Enjoy your HAT****
63 |
--------------------------------------------------------------------------------
/eepromutils/eeptypes.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | /* Atom types */
4 | #define ATOM_INVALID_TYPE 0x0000
5 | #define ATOM_VENDOR_TYPE 0x0001
6 | #define ATOM_GPIO_TYPE 0x0002
7 | #define ATOM_DT_TYPE 0x0003
8 | #define ATOM_CUSTOM_TYPE 0x0004
9 | #define ATOM_HINVALID_TYPE 0xffff
10 |
11 | #define ATOM_VENDOR_NUM 0x0000
12 | #define ATOM_GPIO_NUM 0x0001
13 | #define ATOM_DT_NUM 0x0002
14 |
15 | //minimal sizes of data structures
16 | #define HEADER_SIZE 12
17 | #define ATOM_SIZE 10
18 | #define VENDOR_SIZE 22
19 | #define GPIO_SIZE 30
20 | #define CRC_SIZE 2
21 |
22 | #define GPIO_MIN 2
23 | #define GPIO_COUNT 28
24 |
25 | #define FORMAT_VERSION 0x01
26 |
27 | #define CRC16 0x8005
28 |
29 | /* EEPROM header structure */
30 | struct header_t {
31 | uint32_t signature;
32 | unsigned char ver;
33 | unsigned char res;
34 | uint16_t numatoms;
35 | uint32_t eeplen;
36 | };
37 |
38 | /* Atom structure */
39 | struct atom_t {
40 | uint16_t type;
41 | uint16_t count;
42 | uint32_t dlen;
43 | char* data;
44 | uint16_t crc16;
45 | };
46 |
47 | /* Vendor info atom data */
48 | struct vendor_info_d {
49 | uint32_t serial_1; //least significant
50 | uint32_t serial_2;
51 | uint32_t serial_3;
52 | uint32_t serial_4; //most significant
53 | uint16_t pid;
54 | uint16_t pver;
55 | unsigned char vslen;
56 | unsigned char pslen;
57 | char* vstr;
58 | char* pstr;
59 | };
60 |
61 | /* GPIO map atom data */
62 | struct gpio_map_d {
63 | unsigned char flags;
64 | unsigned char power;
65 | unsigned char pins[GPIO_COUNT];
66 | };
67 |
68 |
69 | uint16_t getcrc(char* data, unsigned int size) {
70 |
71 | uint16_t out = 0;
72 | int bits_read = 0, bit_flag;
73 |
74 | /* Sanity check: */
75 | if((data == NULL) || size==0)
76 | return 0;
77 |
78 | while(size > 0)
79 | {
80 | bit_flag = out >> 15;
81 |
82 | /* Get next bit: */
83 | out <<= 1;
84 | out |= (*data >> bits_read) & 1; // item a) work from the least significant bits
85 |
86 | /* Increment bit counter: */
87 | bits_read++;
88 | if(bits_read > 7)
89 | {
90 | bits_read = 0;
91 | data++;
92 | size--;
93 | }
94 |
95 | /* Cycle check: */
96 | if(bit_flag)
97 | out ^= CRC16;
98 |
99 | }
100 |
101 | // item b) "push out" the last 16 bits
102 | int i;
103 | for (i = 0; i < 16; ++i) {
104 | bit_flag = out >> 15;
105 | out <<= 1;
106 | if(bit_flag)
107 | out ^= CRC16;
108 | }
109 |
110 | // item c) reverse the bits
111 | uint16_t crc = 0;
112 | i = 0x8000;
113 | int j = 0x0001;
114 | for (; i != 0; i >>=1, j <<= 1) {
115 | if (i & out) crc |= j;
116 | }
117 |
118 | return crc;
119 | }
120 |
--------------------------------------------------------------------------------
/eepromutils/eeprom_settings.txt:
--------------------------------------------------------------------------------
1 | ########################################################################
2 | # EEPROM settings text file
3 | #
4 | # Edit this file for your particular board and run through eepmake tool,
5 | # then use eepflash tool to write to attached HAT ID EEPROM
6 | #
7 | # Tools available:
8 | # eepmake Parses EEPROM text file and creates binary .eep file
9 | # eepdump Dumps a binary .eep file as human readable text (for debug)
10 | # eepflash Write or read .eep binary image to/from HAT EEPROM
11 | #
12 | ########################################################################
13 |
14 | ########################################################################
15 | # Vendor info
16 |
17 | # 128 bit UUID. If left at zero eepmake tool will auto-generate
18 | # RFC 4122 compliant UUID
19 | product_uuid 00000000-0000-0000-0000-000000000000
20 |
21 | # 16 bit product id
22 | product_id 0x0000
23 |
24 | # 16 bit product version
25 | product_ver 0x0000
26 |
27 | # ASCII vendor string (max 255 characters)
28 | vendor "ACME Technology Company"
29 |
30 | # ASCII product string (max 255 characters)
31 | product "Special Sensor Board"
32 |
33 |
34 | ########################################################################
35 | # GPIO bank settings, set to nonzero to change from the default.
36 | # NOTE these setting can only be set per BANK, uncommenting any of
37 | # these will force the bank to use the custom setting.
38 |
39 | # drive strength, 0=default, 1-8=2,4,6,8,10,12,14,16mA, 9-15=reserved
40 | gpio_drive 0
41 |
42 | # 0=default, 1=slew rate limiting, 2=no slew limiting, 3=reserved
43 | gpio_slew 0
44 |
45 | # 0=default, 1=hysteresis disabled, 2=hysteresis enabled, 3=reserved
46 | gpio_hysteresis 0
47 |
48 | # If board back-powers Pi via 5V GPIO header pins:
49 | # 0 = board does not back-power
50 | # 1 = board back-powers and can supply the Pi with a minimum of 1.3A
51 | # 2 = board back-powers and can supply the Pi with a minimum of 2A
52 | # 3 = reserved
53 | # If back_power=2 then USB high current mode will be automatically
54 | # enabled on the Pi
55 | back_power 0
56 |
57 | ########################################################################
58 | # GPIO pins, uncomment for GPIOs used on board
59 | # Options for FUNCTION: INPUT, OUTPUT, ALT0-ALT5
60 | # Options for PULL: DEFAULT, UP, DOWN, NONE
61 | # NB GPIO0 and GPIO1 are reserved for ID EEPROM so cannot be set
62 |
63 | # GPIO FUNCTION PULL
64 | # ---- -------- ----
65 | #setgpio 2 INPUT DEFAULT
66 | #setgpio 3 INPUT DEFAULT
67 | #setgpio 4 INPUT DEFAULT
68 | #setgpio 5 INPUT DEFAULT
69 | #setgpio 6 INPUT DEFAULT
70 | #setgpio 7 INPUT DEFAULT
71 | #setgpio 8 INPUT DEFAULT
72 | #setgpio 9 INPUT DEFAULT
73 | #setgpio 10 INPUT DEFAULT
74 | #setgpio 11 INPUT DEFAULT
75 | #setgpio 12 INPUT DEFAULT
76 | #setgpio 13 INPUT DEFAULT
77 | #setgpio 14 INPUT DEFAULT
78 | #setgpio 15 INPUT DEFAULT
79 | #setgpio 16 INPUT DEFAULT
80 | #setgpio 17 INPUT DEFAULT
81 | #setgpio 18 INPUT DEFAULT
82 | #setgpio 19 INPUT DEFAULT
83 | #setgpio 20 INPUT DEFAULT
84 | #setgpio 21 INPUT DEFAULT
85 | #setgpio 22 INPUT DEFAULT
86 | #setgpio 23 INPUT DEFAULT
87 | #setgpio 24 INPUT DEFAULT
88 | #setgpio 25 INPUT DEFAULT
89 | #setgpio 26 INPUT DEFAULT
90 | #setgpio 27 INPUT DEFAULT
91 |
--------------------------------------------------------------------------------
/eepromutils/eepflash.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | MODE="NOT_SET"
4 | FILE="NOT_SET"
5 | TYPE="NOT_SET"
6 |
7 | usage()
8 | {
9 | echo "eepflash: Writes or reads .eep binary image to/from HAT EEPROM on a Raspberry Pi"
10 | echo ""
11 | echo "./eepflash.sh"
12 | echo " -h --help: display this help message"
13 | echo " -r --read: read .eep from the eeprom"
14 | echo " -w --write: write .eep to the eeprom"
15 | echo " -f=file_name --file=file_name: binary .eep file to read to/from"
16 | echo " -t=eeprom_type --type=eeprom_type: eeprom type to use"
17 | echo " We support the following eeprom types:"
18 | echo " -24c32"
19 | echo " -24c64"
20 | echo " -24c128"
21 | echo " -24c256"
22 | echo " -24c512"
23 | echo " -24c1024"
24 | echo ""
25 | }
26 |
27 | if [ "$(id -u)" != "0" ]; then
28 | echo "This script must be run as root" 1>&2
29 | exit 1
30 | fi
31 |
32 | while [ "$1" != "" ]; do
33 | PARAM=`echo $1 | awk -F= '{print $1}'`
34 | VALUE=`echo $1 | awk -F= '{print $2}'`
35 | case $PARAM in
36 | -h | --help)
37 | usage
38 | exit
39 | ;;
40 | -r | --read)
41 | MODE="read"
42 | ;;
43 | -w | --write)
44 | MODE="write"
45 | ;;
46 | -t | --type)
47 | if [ "$VALUE" = "24c32" ] || [ "$VALUE" = "24c64" ] || [ "$VALUE" = "24c128" ] ||
48 | [ "$VALUE" = "24c256" ] || [ "$VALUE" = "24c512" ] || [ "$VALUE" = "24c1024" ]; then
49 | TYPE=$VALUE
50 | else
51 | echo "ERROR: Unrecognised eeprom type. Try -h for help"
52 | exit 1
53 | fi
54 | ;;
55 | -f | --file)
56 | FILE=$VALUE
57 | ;;
58 | *)
59 | echo "ERROR: unknown parameter \"$PARAM\""
60 | usage
61 | exit 1
62 | ;;
63 | esac
64 | shift
65 | done
66 |
67 | if [ "$MODE" = "NOT_SET" ]; then
68 | echo "You need to set mode (read or write). Try -h for help."
69 | exit 1
70 | elif [ "$FILE" = "NOT_SET" ]; then
71 | echo "You need to set binary .eep file to read to/from. Try -h for help."
72 | exit 1
73 | elif [ "$TYPE" = "NOT_SET" ]; then
74 | echo "You need to set eeprom type. Try -h for help."
75 | exit 1
76 | fi
77 |
78 | echo "This will attempt to talk to an eeprom at i2c address 0x50. Make sure there is an eeprom at this address."
79 | echo "This script comes with ABSOLUTELY no warranty. Continue only if you know what you are doing."
80 |
81 | while true; do
82 | read -p "Do you wish to continue? (yes/no): " yn
83 | case $yn in
84 | yes | Yes ) break;;
85 | no | No ) exit;;
86 | * ) echo "Please type yes or no.";;
87 | esac
88 | done
89 |
90 | modprobe i2c_dev
91 | if [ -e "/dev/i2c-0" ]; then
92 | BUS=0
93 | elif [ -e "/dev/i2c-3" ]; then
94 | BUS=3
95 | else
96 | dtoverlay i2c-gpio i2c_gpio_sda=0 i2c_gpio_scl=1
97 | rc=$?
98 | if [ $rc != 0 ]; then
99 | echo "Loading of i2c-gpio dtoverlay failed. Do an rpi-update (and maybe apt-get update; apt-get upgrade)."
100 | exit $rc
101 | fi
102 | if [ -e "/dev/i2c-3" ]; then
103 | BUS=3
104 | else
105 | echo "Expected I2C bus (i2c-3) not found."
106 | fi
107 | fi
108 | modprobe at24
109 | rc=$?
110 | if [ $rc != 0 ]; then
111 | echo "Modprobe of at24 failed. Do an rpi-update."
112 | exit $rc
113 | fi
114 |
115 | SYS=/sys/class/i2c-adapter/i2c-$BUS
116 |
117 | if [ ! -d "$SYS/$BUS-0050" ]; then
118 | echo "$TYPE 0x50" > $SYS/new_device
119 | fi
120 |
121 |
122 | if [ "$MODE" = "write" ]
123 | then
124 | echo "Writing..."
125 | dd if=$FILE of=$SYS/$BUS-0050/eeprom
126 | rc=$?
127 | elif [ "$MODE" = "read" ]
128 | then
129 | echo "Reading..."
130 | dd if=$SYS/$BUS-0050/eeprom of=$FILE
131 | rc=$?
132 | fi
133 |
134 | if [ $rc != 0 ]; then
135 | echo "Error doing I/O operation."
136 | exit $rc
137 | else
138 | echo "Done."
139 | fi
140 |
--------------------------------------------------------------------------------
/eepromutils/eepdump.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "eeptypes.h"
8 |
9 | struct header_t header;
10 | struct atom_t atom;
11 | struct vendor_info_d vinf;
12 | struct gpio_map_d gpiomap;
13 | unsigned char* data;
14 |
15 | int read_bin(char *in, char *outf) {
16 |
17 | uint16_t crc;
18 | FILE *fp, *out;
19 | int i,j;
20 |
21 | fp=fopen(in, "r");
22 | if (!fp) {
23 | printf("Error reading file %s\n", in);
24 | return -1;
25 | }
26 |
27 | out=fopen(outf, "w");
28 | if (!out) {
29 | printf("Error writing file %s\n", outf);
30 | return -1;
31 | }
32 |
33 | if (!fread(&header, sizeof(header), 1, fp)) goto err;
34 |
35 | fprintf(out, "# ---------- Dump generated by eepdump handling format version 0x%02x ----------\n#\n", FORMAT_VERSION);
36 |
37 | if (FORMAT_VERSION!=header.ver) fprintf(out, "# WARNING: format version mismatch!!!\n");
38 |
39 | fprintf(out, "# --Header--\n# signature=0x%08x\n# version=0x%02x\n# reserved=%u\n# numatoms=%u\n# eeplen=%u\n# ----------\n\n\n", header.signature, header.ver, header.res, header.numatoms, header.eeplen);
40 |
41 |
42 | for (i = 0; i>16, vinf.serial_3 & 0xffff, vinf.serial_2>>16, vinf.serial_2 & 0xffff, vinf.serial_1);
69 | fprintf(out, "product_id 0x%04x\n", vinf.pid);
70 | fprintf(out, "product_ver 0x%04x\n", vinf.pver);
71 |
72 | vinf.vstr = (char *) malloc(vinf.vslen+1);
73 | vinf.pstr = (char *) malloc(vinf.pslen+1);
74 |
75 | if (!fread(vinf.vstr, vinf.vslen, 1, fp)) goto err;
76 | if (!fread(vinf.pstr, vinf.pslen, 1, fp)) goto err;
77 | //close strings
78 | vinf.vstr[vinf.vslen] = 0;
79 | vinf.pstr[vinf.pslen] = 0;
80 |
81 | fprintf(out, "vendor \"%s\" # length=%u\n", vinf.vstr, vinf.vslen);
82 | fprintf(out, "product \"%s\" # length=%u\n", vinf.pstr, vinf.pslen);
83 |
84 | if (!fread(&crc, CRC_SIZE, 1, fp)) goto err;
85 |
86 | } else if (atom.type==ATOM_GPIO_TYPE) {
87 | //decode GPIO map
88 | if (!fread(&gpiomap, GPIO_SIZE, 1, fp)) goto err;
89 |
90 | fprintf(out, "# GPIO map info\n");
91 | fprintf(out, "gpio_drive %d\n", gpiomap.flags & 15); //1111
92 | fprintf(out, "gpio_slew %d\n", (gpiomap.flags & 48)>>4); //110000
93 | fprintf(out, "gpio_hysteresis %d\n", (gpiomap.flags & 192)>>6); //11000000
94 | fprintf(out, "back_power %d\n", gpiomap.power);
95 | fprintf(out, "# GPIO FUNCTION PULL\n# ---- -------- ----\n");
96 |
97 | for (j = 0; j<28; j++) {
98 | if (gpiomap.pins[j] & (1<<7)) {
99 | //board uses this pin
100 |
101 | char *pull_str = "INVALID";
102 | switch ((gpiomap.pins[j] & 96)>>5) { //1100000
103 | case 0: pull_str = "DEFAULT";
104 | break;
105 | case 1: pull_str = "UP";
106 | break;
107 | case 2: pull_str = "DOWN";
108 | break;
109 | case 3: pull_str = "NONE";
110 | break;
111 | }
112 |
113 | char *func_str = "INVALID";
114 | switch ((gpiomap.pins[j] & 7)) { //111
115 | case 0: func_str = "INPUT";
116 | break;
117 | case 1: func_str = "OUTPUT";
118 | break;
119 | case 4: func_str = "ALT0";
120 | break;
121 | case 5: func_str = "ALT1";
122 | break;
123 | case 6: func_str = "ALT2";
124 | break;
125 | case 7: func_str = "ALT3";
126 | break;
127 | case 3: func_str = "ALT4";
128 | break;
129 | case 2: func_str = "ALT5";
130 | break;
131 | }
132 |
133 | fprintf(out, "setgpio %d %s %s\n", j, func_str, pull_str);
134 | }
135 | }
136 |
137 | if (!fread(&crc, CRC_SIZE, 1, fp)) goto err;
138 |
139 | } else if (atom.type==ATOM_DT_TYPE) {
140 | //decode DT blob
141 |
142 | fprintf(out, "dt_blob");
143 | data = (char *) malloc(atom.dlen-CRC_SIZE);
144 | if (!fread(data, atom.dlen-CRC_SIZE, 1, fp)) goto err;
145 |
146 | for (j = 0; j
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "eeptypes.h"
14 |
15 | #define HEADER_SIGN 0x69502d52 //"R-Pi" in ASCII reversed for endianness
16 |
17 | //todo: larger initial mallocs
18 |
19 | struct header_t header;
20 | struct atom_t *custom_atom, vinf_atom, gpio_atom, dt_atom;
21 | struct vendor_info_d* vinf;
22 | struct gpio_map_d* gpiomap;
23 |
24 | bool product_serial_set, product_id_set, product_ver_set, vendor_set, product_set,
25 | gpio_drive_set, gpio_slew_set, gpio_hysteresis_set, gpio_power_set;
26 |
27 | bool data_receive, has_dt, receive_dt;
28 |
29 | char **data;
30 | char *current_atom; //rearranged to write out
31 | unsigned int data_len, custom_ct, total_size, data_cap, custom_cap;
32 |
33 |
34 | int write_binary(char* out) {
35 | FILE *fp;
36 | int i, offset;
37 | short crc;
38 |
39 | fp=fopen(out, "wb");
40 | if (!fp) {
41 | printf("Error writing file %s\n", out);
42 | return -1;
43 | }
44 |
45 | fwrite(&header, sizeof(header), 1, fp);
46 |
47 |
48 | current_atom = (char *) malloc(vinf_atom.dlen+ATOM_SIZE-CRC_SIZE);
49 | offset = 0;
50 | //vendor information atom first part
51 | memcpy(current_atom, &vinf_atom, ATOM_SIZE-CRC_SIZE);
52 | offset += ATOM_SIZE-2;
53 | //data first part
54 | memcpy(current_atom+offset, vinf_atom.data, VENDOR_SIZE);
55 | offset += VENDOR_SIZE;
56 | //data strings
57 | memcpy(current_atom+offset, vinf->vstr, vinf->vslen);
58 | offset += vinf->vslen;
59 | memcpy(current_atom+offset, vinf->pstr, vinf->pslen);
60 | offset += vinf->pslen;
61 | //vinf last part
62 | crc = getcrc(current_atom, offset);
63 | memcpy(current_atom+offset, &crc, CRC_SIZE);
64 | offset += CRC_SIZE;
65 |
66 | fwrite(current_atom, offset, 1, fp);
67 | free(current_atom);
68 |
69 | current_atom = (char *) malloc(gpio_atom.dlen+ATOM_SIZE-CRC_SIZE);
70 | offset = 0;
71 | //GPIO map first part
72 | memcpy(current_atom, &gpio_atom, ATOM_SIZE-CRC_SIZE);
73 | offset += ATOM_SIZE-CRC_SIZE;
74 | //GPIO data
75 | memcpy(current_atom+offset, gpiomap, GPIO_SIZE);
76 | offset += GPIO_SIZE;
77 | //GPIO map last part
78 | crc = getcrc(current_atom, offset);
79 | memcpy(current_atom+offset, &crc, CRC_SIZE);
80 | offset += CRC_SIZE;
81 |
82 | fwrite(current_atom, offset, 1, fp);
83 | free(current_atom);
84 |
85 | if (has_dt) {
86 | printf("Writing out DT...\n");
87 | current_atom = (char *) malloc(dt_atom.dlen+ATOM_SIZE-CRC_SIZE);
88 | offset = 0;
89 |
90 | memcpy(current_atom, &dt_atom, ATOM_SIZE-CRC_SIZE);
91 | offset += ATOM_SIZE-CRC_SIZE;
92 |
93 | memcpy(current_atom+offset, dt_atom.data, dt_atom.dlen-CRC_SIZE);
94 | offset += dt_atom.dlen-CRC_SIZE;
95 |
96 | crc = getcrc(current_atom, offset);
97 | memcpy(current_atom+offset, &crc, CRC_SIZE);
98 | offset += CRC_SIZE;
99 |
100 | fwrite(current_atom, offset, 1, fp);
101 | free(current_atom);
102 | }
103 |
104 | for (i = 0; iserial_4,
203 | &high1, &vinf->serial_3, &high2, &vinf->serial_2, &vinf->serial_1);
204 |
205 | vinf->serial_3 |= high1<<16;
206 | vinf->serial_2 |= high2<<16;
207 |
208 | if ((vinf->serial_4==0) && (vinf->serial_3==0) && (vinf->serial_2==0) && (vinf->serial_1==0)) {
209 | //read 128 random bits from /dev/urandom
210 | int random_file = open("/dev/urandom", O_RDONLY);
211 | ssize_t result = read(random_file, &vinf->serial_1, 16);
212 | close(random_file);
213 | if (result <= 0) printf("Unable to read from /dev/urandom to set up UUID");
214 | else {
215 | //put in the version
216 | vinf->serial_3 = (vinf->serial_3 & 0xffff0fff) | 0x00004000;
217 |
218 | //put in the variant
219 | vinf->serial_2 = (vinf->serial_2 & 0x3fffffff) | 0x80000000;
220 |
221 | printf("UUID=%08x-%04x-%04x-%04x-%04x%08x\n", vinf->serial_4, vinf->serial_3>>16, vinf->serial_3 & 0xffff, vinf->serial_2>>16, vinf->serial_2 & 0xffff, vinf->serial_1);
222 | }
223 |
224 | }
225 |
226 | } else if (strcmp(cmd, "product_id")==0) {
227 | product_id_set = true; //required field
228 | sscanf(c, "%100s %hx", cmd, &vinf->pid);
229 |
230 | } else if (strcmp(cmd, "product_ver")==0) {
231 | product_ver_set = true; //required field
232 | sscanf(c, "%100s %hx", cmd, &vinf->pver);
233 |
234 | } else if (strcmp(cmd, "vendor")==0) {
235 | vendor_set = true; //required field
236 |
237 | vinf->vstr = (char*) malloc (256);
238 | sscanf(c, "%100s \"%255[^\"]\"", cmd, vinf->vstr);
239 |
240 | total_size-=vinf->vslen;
241 | vinf_atom.dlen-=vinf->vslen;
242 |
243 | vinf->vslen = strlen(vinf->vstr);
244 |
245 | total_size+=vinf->vslen;
246 | vinf_atom.dlen+=vinf->vslen;
247 |
248 | } else if (strcmp(cmd, "product")==0) {
249 | product_set = true; //required field
250 |
251 | vinf->pstr = (char*) malloc (256);
252 | sscanf(c, "%100s \"%255[^\"]\"", cmd, vinf->pstr);
253 |
254 | total_size-=vinf->pslen;
255 | vinf_atom.dlen-=vinf->pslen;
256 |
257 | vinf->pslen = strlen(vinf->pstr);
258 |
259 | total_size+=vinf->pslen;
260 | vinf_atom.dlen+=vinf->pslen;
261 | }
262 |
263 | /* GPIO map related part */
264 | else if (strcmp(cmd, "gpio_drive")==0) {
265 | gpio_drive_set = true; //required field
266 |
267 | sscanf(c, "%100s %1x", cmd, &val);
268 | if (val>8 || val<0) printf("Warning: gpio_drive property in invalid region, using default value instead\n");
269 | else gpiomap->flags |= val;
270 |
271 |
272 | } else if (strcmp(cmd, "gpio_slew")==0) {
273 | gpio_slew_set = true; //required field
274 |
275 | sscanf(c, "%100s %1x", cmd, &val);
276 |
277 | if (val>2 || val<0) printf("Warning: gpio_slew property in invalid region, using default value instead\n");
278 | else gpiomap->flags |= val<<4;
279 |
280 | } else if (strcmp(cmd, "gpio_hysteresis")==0) {
281 | gpio_hysteresis_set = true; //required field
282 |
283 | sscanf(c, "%100s %1x", cmd, &val);
284 |
285 | if (val>2 || val<0) printf("Warning: gpio_hysteresis property in invalid region, using default value instead\n");
286 | else gpiomap->flags |= val<<6;
287 |
288 | } else if (strcmp(cmd, "back_power")==0) {
289 | gpio_power_set = true; //required field
290 |
291 | sscanf(c, "%100s %1x", cmd, &val);
292 |
293 | if (val>2 || val<0) printf("Warning: back_power property in invalid region, using default value instead\n");
294 | else gpiomap->power = val;
295 |
296 | } else if (strcmp(cmd, "setgpio")==0) {
297 | fn = (char*) malloc (101);
298 | pull = (char*) malloc (101);
299 |
300 | sscanf(c, "%100s %d %100s %100s", cmd, &val, fn, pull);
301 |
302 | if (val=GPIO_COUNT) printf("Error: GPIO number out of bounds\n");
303 | else {
304 | valid = true;
305 | pin = 0;
306 |
307 | if (strcmp(fn, "INPUT")==0) {
308 | //no action
309 | } else if (strcmp(fn, "OUTPUT")==0) {
310 | pin |= 1;
311 | } else if (strcmp(fn, "ALT0")==0) {
312 | pin |= 4;
313 | } else if (strcmp(fn, "ALT1")==0) {
314 | pin |= 5;
315 | } else if (strcmp(fn, "ALT2")==0) {
316 | pin |= 6;
317 | } else if (strcmp(fn, "ALT3")==0) {
318 | pin |= 7;
319 | } else if (strcmp(fn, "ALT4")==0) {
320 | pin |= 3;
321 | } else if (strcmp(fn, "ALT5")==0) {
322 | pin |= 2;
323 | } else {
324 | printf("Error at setgpio: function type not recognised\n");
325 | valid=false;
326 | }
327 |
328 | if (strcmp(pull, "DEFAULT")==0) {
329 | //no action
330 | } else if (strcmp(pull, "UP")==0) {
331 | pin |= 1<<5;
332 | } else if (strcmp(pull, "DOWN")==0) {
333 | pin |= 2<<5;
334 | } else if (strcmp(pull, "NONE")==0) {
335 | pin |= 3<<5;
336 | } else {
337 | printf("Error at setgpio: pull type not recognised\n");
338 | valid=false;
339 | }
340 |
341 | pin |= 1<<7; //board uses this pin
342 |
343 | if (valid) gpiomap->pins[val] = pin;
344 | }
345 | }
346 |
347 | /* DT atom related part */
348 | else if (strcmp(cmd, "dt_blob")==0) {
349 | finish_data();
350 |
351 | has_dt = true;
352 | c+=strlen("dt_blob");
353 |
354 | receive_dt=true;
355 | data_receive=true;
356 |
357 | data_len = 0;
358 | data_cap = 4;
359 | data = &dt_atom.data;
360 | *data = (char *) malloc(data_cap);
361 |
362 | parse_data(c);
363 | continue_data = true;
364 |
365 | }
366 |
367 | /* Custom data related part */
368 | else if (strcmp(cmd, "custom_data")==0) {
369 | finish_data();
370 |
371 | c+=strlen("custom_data");
372 |
373 | if (custom_cap == custom_ct) {
374 | custom_cap *= 2;
375 | custom_atom = (struct atom_t*) realloc(custom_atom, custom_cap * sizeof(struct atom_t));
376 | }
377 |
378 | receive_dt=false;
379 | data_receive=true;
380 |
381 | data_len = 0;
382 | data_cap = 4;
383 | data = &custom_atom[custom_ct].data;
384 | *data = (char *) malloc(data_cap);
385 |
386 | parse_data(c);
387 | continue_data = true;
388 |
389 | } else if (strcmp(cmd, "end") ==0) {
390 | //close last data atom
391 | continue_data=false;
392 | }
393 | /* Incoming data */
394 | else if (data_receive) {
395 | parse_data(c);
396 | continue_data = true;
397 | }
398 |
399 |
400 | if (!continue_data) finish_data();
401 |
402 | }
403 |
404 | int read_text(char* in) {
405 | FILE * fp;
406 | char * line = NULL;
407 | char * c = NULL;
408 | size_t len = 0;
409 | ssize_t read;
410 | char *comment = NULL;
411 | int atomct = 2;
412 | int linect = 0;
413 | char * command = (char*) malloc (101);
414 | int i;
415 |
416 | has_dt = false;
417 |
418 | printf("Opening file %s for read\n", in);
419 |
420 | fp = fopen(in, "r");
421 | if (fp == NULL) {
422 | printf("Error opening input file\n");
423 | return -1;
424 | }
425 |
426 | //allocating memory and setting up required atoms
427 | custom_cap = 1;
428 | custom_atom = (struct atom_t*) malloc(sizeof(struct atom_t) * custom_cap);
429 |
430 | total_size=ATOM_SIZE*2+HEADER_SIZE+VENDOR_SIZE+GPIO_SIZE;
431 |
432 | vinf_atom.type = ATOM_VENDOR_TYPE;
433 | vinf_atom.count = ATOM_VENDOR_NUM;
434 | vinf = (struct vendor_info_d *) malloc(sizeof(struct vendor_info_d));
435 | vinf_atom.data = (char *)vinf;
436 | vinf_atom.dlen = VENDOR_SIZE + CRC_SIZE;
437 |
438 | gpio_atom.type = ATOM_GPIO_TYPE;
439 | gpio_atom.count = ATOM_GPIO_NUM;
440 | gpiomap = (struct gpio_map_d *) malloc(sizeof(struct gpio_map_d));
441 | gpio_atom.data = (char *)gpiomap;
442 | gpio_atom.dlen = GPIO_SIZE + CRC_SIZE;
443 |
444 | while ((read = getline(&line, &len, fp)) != -1) {
445 | linect++;
446 | c = line;
447 |
448 | for (i=0; i3) {
577 | if (strcmp(argv[3], "-c")==0) {
578 | custom_o=4;
579 | } else {
580 | //DT file specified
581 | if (dt_atom.dlen) total_size-=(ATOM_SIZE +dt_atom.dlen - CRC_SIZE);
582 | ret = read_dt(argv[3]);
583 | if (ret) {
584 | printf("Error reading DT file, aborting\n");
585 | return 0;
586 | }
587 | }
588 | }
589 |
590 | if (argc>4 && strcmp(argv[4], "-c")==0) custom_o = 5;
591 |
592 | if (custom_o)
593 | for (i = custom_o; i