├── .gitignore
├── .gitmodules
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── src
├── Makefile
├── ansible_arc.c
├── ansible_arc.h
├── ansible_grid.c
├── ansible_grid.h
├── ansible_ii_leader.c
├── ansible_ii_leader.h
├── ansible_midi.c
├── ansible_midi.h
├── ansible_preset_docdef.c
├── ansible_preset_docdef.h
├── ansible_tt.c
├── ansible_tt.h
├── ansible_usb_disk.c
├── ansible_usb_disk.h
├── config.mk
├── flash.sh
├── gitversion.h
├── main.c
├── main.h
└── update-firmware.command
└── tools
└── flash_tools
├── .gitignore
├── README.md
├── commands
├── __init__.py
├── docdef
│ ├── docdef_writer.py
│ └── write_docdef.py
├── extract
│ ├── extract_presets.py
│ └── extractor.py
├── firmware_tool.py
└── repl
│ ├── read_eval_print_loop.py
│ └── repl.py
├── main.py
├── preset_schema.py
├── preset_schemata.py
├── requirements.pip
└── schemata
├── README.md
├── ansible
├── __init__.py
├── ansible_preset_schema.py
├── v161.py
├── v161_es.py
├── v300.py
└── vnext.py
└── teletype
├── __init__.py
├── teletype_preset_schema.py
└── v300.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.zip
3 | src/gitversion.c
4 |
5 | # Object files
6 | *.o
7 | *.ko
8 | *.obj
9 | *.elf
10 | *.d
11 | *~
12 | *#
13 | .#*
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Atmel binary artifacts
40 | *.bin
41 | *.lss
42 | *.sym
43 | *.map
44 |
45 | # Debug files
46 | *.dSYM/
47 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libavr32"]
2 | path = libavr32
3 | url = https://github.com/monome/libavr32.git
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | install:
4 | - pushd $HOME
5 | # TODO: move toolchain to monome repo
6 | - git clone https://github.com/samdoshi/avr32-toolchain-linux.git deps/avr32-toolchain-linux
7 | - cd deps/avr32-toolchain-linux
8 | - tar xvfz avr32-gnu-toolchain-3.4.3.820-linux.any.x86_64.tar.gz
9 | - mv avr32-gnu-toolchain-linux_x86_64 $HOME/avr32-tools
10 | - unzip avr32-headers-6.2.0.742.zip -d $HOME/avr32-tools/avr32/include
11 | - popd
12 |
13 | script:
14 | - cd src
15 | - PATH="$HOME/avr32-tools/bin:$PATH" make
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v3.1.1
2 |
3 | - **NEW**: latest grid support
4 |
5 |
6 | ## v3.1.0
7 | - **FIX**: tuning customization behavior in midi modes
8 | - **FIX**: send original rather than customized pitch table values to ii followers
9 | - **FIX**: bugs preventing saving / loading some presets to USB
10 | - **FIX**: disable i2c during preset writes to prevent possible loss of data
11 | - **FIX**: improve delay when connecting grid and arc
12 | - **FIX**: reset JF velocity when exiting leader mode
13 | - **NEW**: freeze one pattern for editing while meta sequence continues to run
14 | - **NEW**: optionally reset the entire meta pattern on a reset trigger
15 | - **NEW**: optionally always tie notes when duration is maxed
16 | - **NEW**: Disting EX as ii follower
17 | - **NEW**: W/syn as ii follower
18 | - **NEW**: crow as ii follower
19 | - **NEW**: supports new `ES.CV` teletype op
20 |
21 |
22 | ## v3.0.0
23 |
24 | - **NEW**: i2c leader mode for controlling Just Friends, TELEXo, or ER-301 from ansible
25 | - **NEW**: kria: playhead shows on probability page
26 | - **FIX**: avoid some types of i2c crashes
27 | - **FIX**: kria: glitches when stopping and restarting external clock
28 | - **NEW**: compensate-shift scales by holding scale key when changing scale notes
29 | - **NEW**: supports new kria teletype ops: `KR.CUE`, `KR.DIR`, `KR.DUR`
30 |
31 |
32 | ## v2.0.0
33 |
34 | - **FIX**: meadowphysics: fix trigger behavior in 1 CV/TR mode
35 | - **NEW**: earthsea grid app
36 | - **NEW**: save/load presets to USB disk
37 | - **NEW**: grid interface for tuning CV outputs
38 | - **NEW**: kria: step direction modes (forward, reverse, pendulum, drunk, random)
39 | - **NEW**: kria: track-wide octave shift
40 | - **NEW**: kria: quantize clock division changes to loop endpoints (configurable)
41 | - **NEW**: kria: sync clock division changes across parameters or tracks (configurable)
42 | - **NEW**: kria: toggle individual triggers when ratcheting
43 | - **NEW**: kria: clock advances the note only when a trigger happens (configurable)
44 | - **NEW**: kria: ability to have note sync ON and loop sync OFF
45 | - **NEW**: shift the value of scale notes without affecting the rest of the scale
46 | - **NEW**: supports new `ANS` teletype ops for grid, arc, and app state
47 |
48 |
49 | for changes in older versions see [releases](https://github.com/monome/ansible/releases)
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ansible
2 |
3 | [](https://travis-ci.org/monome/ansible)
4 |
5 | http://monome.org/docs/modular/ansible
6 |
7 | far communicator, speaks openly.
8 |
9 | grid- arc- teletype- midi- enabled. requires at least one of these.
10 |
11 |
12 | ---
13 |
14 | - MIDI design and code by @ngwese
15 | - earthsea implementation by @scanner-darkly
16 | - preset JSON engine by @csboling
17 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | # List of available make goals:
2 | #
3 | # all Default target, builds the project
4 | # clean Clean up the project
5 | # rebuild Rebuild the project
6 | #
7 | # isp Use BatchISP instead of avr32program when interfacing
8 | # the target device.
9 | #
10 | # chiperase Perform a JTAG chip erase command
11 | # cpuinfo Get CPU information
12 | # debug Open a debug connection with the MCU
13 | # erase Perform a flash erase
14 | # halt Stop CPU execution
15 | # program Program MCU memory from ELF output file
16 | # reset Reset MCU
17 | # readregs Read CPU registers
18 | # run Start CPU execution
19 | # secureflash Protect chip by setting security bit
20 | #
21 | # doc Build the documentation
22 | # cleandoc Clean up the documentation
23 | # rebuilddoc Rebuild the documentation
24 | #
25 | #
26 | # Copyright (c) 2009-2010 Atmel Corporation. All rights reserved.
27 | #
28 | # \asf_license_start
29 | #
30 | # \page License
31 | #
32 | # Redistribution and use in source and binary forms, with or without
33 | # modification, are permitted provided that the following conditions are met:
34 | #
35 | # 1. Redistributions of source code must retain the above copyright notice,
36 | # this list of conditions and the following disclaimer.
37 | #
38 | # 2. Redistributions in binary form must reproduce the above copyright notice,
39 | # this list of conditions and the following disclaimer in the documentation
40 | # and/or other materials provided with the distribution.
41 | #
42 | # 3. The name of Atmel may not be used to endorse or promote products derived
43 | # from this software without specific prior written permission.
44 | #
45 | # 4. This software may only be redistributed and used in connection with an
46 | # Atmel microcontroller product.
47 | #
48 | # THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
49 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
51 | # EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
52 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
57 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 | # POSSIBILITY OF SUCH DAMAGE.
59 | #
60 | # \asf_license_stop
61 | #
62 |
63 | # Include the common Makefile, which will also include the project specific
64 | # config.mk file.
65 | MAKEFILE_PATH = ../libavr32/asf/avr32/utils/make/Makefile.avr32.in
66 | include $(MAKEFILE_PATH)
67 |
--------------------------------------------------------------------------------
/src/ansible_arc.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "main.h"
4 |
5 | #define ARC_NUM_PRESETS 8
6 |
7 | typedef struct {
8 | uint16_t pattern[4][16];
9 | uint8_t note[4][16];
10 | bool mode[4];
11 | bool all[4];
12 | uint8_t now;
13 | uint8_t start;
14 | int8_t len;
15 | uint8_t dir;
16 | uint8_t scale[4];
17 | uint8_t octave[4];
18 | uint16_t offset[4];
19 | uint16_t range[4];
20 | uint16_t slew[4];
21 | } levels_data_t;
22 |
23 | extern levels_data_t l;
24 |
25 | typedef struct {
26 | // uint32_t clock_period;
27 | uint8_t preset;
28 | levels_data_t l[ARC_NUM_PRESETS];
29 | } levels_state_t;
30 |
31 | typedef struct {
32 | uint16_t pos[4];
33 | int16_t speed[4];
34 | int8_t mult[4];
35 | uint8_t range[4];
36 | uint8_t mode;
37 | uint8_t shape;
38 | uint8_t friction;
39 | uint16_t force;
40 | uint8_t div[4];
41 | } cycles_data_t;
42 |
43 | extern cycles_data_t c;
44 |
45 | typedef struct {
46 | // uint32_t clock_period;
47 | uint8_t preset;
48 | cycles_data_t c[ARC_NUM_PRESETS];
49 | } cycles_state_t;
50 |
51 | void set_mode_arc(void);
52 | void handler_ArcFrontShort(s32 data);
53 | void handler_ArcFrontLong(s32 data);
54 | void arc_keytimer(void);
55 | void refresh_arc_preset(void);
56 | void handler_ArcPresetEnc(s32 data);
57 | void handler_ArcPresetKey(s32 data);
58 | void ii_arc(uint8_t* data, uint8_t len);
59 |
60 | void default_levels(void);
61 | void init_levels(void);
62 | void resume_levels(void);
63 | void clock_levels(uint8_t phase);
64 | void ii_levels(uint8_t *d, uint8_t l);
65 | void refresh_levels(void);
66 | void refresh_levels_change(void);
67 | void refresh_levels_config(void);
68 | void handler_LevelsEnc(s32 data);
69 | void handler_LevelsRefresh(s32 data);
70 | void handler_LevelsKey(s32 data);
71 | void handler_LevelsTr(s32 data);
72 | void handler_LevelsTrNormal(s32 data);
73 |
74 | void default_cycles(void);
75 | void init_cycles(void);
76 | void resume_cycles(void);
77 | void clock_cycles(uint8_t phase);
78 | void ii_cycles(uint8_t *d, uint8_t l);
79 | void refresh_cycles(void);
80 | void refresh_cycles_config(void);
81 | void refresh_cycles_config_range(void);
82 | void refresh_cycles_config_div(void);
83 | void handler_CyclesEnc(s32 data);
84 | void handler_CyclesRefresh(s32 data);
85 | void handler_CyclesKey(s32 data);
86 | void handler_CyclesTr(s32 data);
87 | void handler_CyclesTrNormal(s32 data);
88 |
--------------------------------------------------------------------------------
/src/ansible_grid.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define R0 0
4 | #define R1 16
5 | #define R2 32
6 | #define R3 48
7 | #define R4 64
8 | #define R5 80
9 | #define R6 96
10 | #define R7 112
11 |
12 | #define GRID_PRESETS 8
13 |
14 | #define KRIA_NUM_TRACKS 4
15 | #define KRIA_NUM_PARAMS 7
16 | #define KRIA_NUM_PATTERNS 16
17 |
18 | typedef enum {
19 | krDirForward = 0,
20 | krDirReverse = 1,
21 | krDirTriangle = 2,
22 | krDirDrunk = 3,
23 | krDirRandom = 4,
24 | } kria_direction;
25 |
26 | #define ES_EVENTS_PER_PATTERN 128
27 | #define ES_EDGE_PATTERN 0
28 | #define ES_EDGE_FIXED 1
29 | #define ES_EDGE_DRONE 2
30 |
31 | typedef struct {
32 | u8 tr[16];
33 | s8 oct[16];
34 | u8 note[16];
35 | u8 dur[16];
36 | u8 rpt[16];
37 | u8 rptBits[16];
38 | u8 alt_note[16];
39 | u8 glide[16];
40 |
41 | u8 p[KRIA_NUM_PARAMS][16];
42 |
43 | // u8 ptr[16];
44 | // u8 poct[16];
45 | // u8 pnote[16];
46 | // u8 pdur[16];
47 |
48 | u8 dur_mul;
49 | kria_direction direction;
50 | u8 advancing[KRIA_NUM_PARAMS];
51 | u8 octshift;
52 |
53 | u8 lstart[KRIA_NUM_PARAMS];
54 | u8 lend[KRIA_NUM_PARAMS];
55 | u8 llen[KRIA_NUM_PARAMS];
56 | u8 lswap[KRIA_NUM_PARAMS];
57 | u8 tmul[KRIA_NUM_PARAMS];
58 |
59 | bool tt_clocked;
60 | bool trigger_clocked;
61 | } kria_track;
62 |
63 | typedef struct {
64 | kria_track t[4];
65 | u8 scale;
66 | } kria_pattern;
67 |
68 | typedef struct {
69 | kria_pattern p[KRIA_NUM_PATTERNS];
70 | uint8_t pattern;
71 | uint8_t meta_pat[64];
72 | uint8_t meta_steps[64];
73 | uint8_t meta_start;
74 | uint8_t meta_end;
75 | uint8_t meta_len;
76 | uint8_t meta_lswap;
77 | uint8_t glyph[8];
78 | } kria_data_t;
79 |
80 | extern kria_data_t k;
81 |
82 | typedef enum {
83 | krSyncNone = 0x00,
84 | krSyncTimeDiv = 0x01,
85 | } kria_sync_mode_t;
86 |
87 | typedef struct {
88 | uint32_t clock_period;
89 | kria_sync_mode_t sync_mode;
90 | uint8_t preset;
91 | bool note_sync;
92 | uint8_t loop_sync;
93 | bool note_div_sync;
94 | uint8_t div_sync;
95 | uint8_t cue_div;
96 | uint8_t cue_steps;
97 | uint8_t meta;
98 | bool meta_reset_all;
99 | bool dur_tie_mode;
100 | kria_data_t k[GRID_PRESETS];
101 | } kria_state_t;
102 |
103 | typedef enum {
104 | mTr, mNote, mOct, mDur, mRpt, mAltNote, mGlide, mScale, mPattern
105 | } kria_modes_t;
106 |
107 | typedef enum {
108 | modNone, modLoop, modTime, modProb
109 | } kria_mod_modes_t;
110 |
111 | typedef struct {
112 | u8 track;
113 | kria_modes_t mode;
114 | kria_mod_modes_t mod_mode;
115 | bool mode_is_alt;
116 | u8* buffer;
117 | } kria_view_t;
118 |
119 |
120 | typedef struct {
121 | // s8 position[8]; // current position in cycle
122 | // u8 tick[8]; // position in speed countdown
123 | // u8 pushed[8]; // manual key reset
124 |
125 | u8 count[8]; // length of cycle
126 | s8 speed[8]; // speed of cycle
127 | u8 min[8];
128 | u8 max[8];
129 | u8 trigger[8];
130 | u8 toggle[8];
131 | u8 rules[8];
132 | u8 rule_dests[8];
133 | u8 sync[8]; // if true, reset dest rule to count
134 | u8 rule_dest_targets[8];
135 | u8 smin[8];
136 | u8 smax[8];
137 |
138 | u8 scale;
139 | u8 glyph[8];
140 | } mp_data_t;
141 |
142 | extern mp_data_t m;
143 |
144 | typedef struct {
145 | uint8_t preset;
146 | uint8_t sound;
147 | uint8_t voice_mode;
148 | mp_data_t m[GRID_PRESETS];
149 | } mp_state_t;
150 |
151 |
152 |
153 |
154 | typedef enum {
155 | es_stopped,
156 | es_armed,
157 | es_recording,
158 | es_playing
159 | } es_mode_t;
160 |
161 | typedef enum {
162 | es_main,
163 | es_patterns_held,
164 | es_patterns
165 | } es_view_t;
166 |
167 | typedef struct {
168 | u8 active;
169 | s8 x;
170 | s8 y;
171 | u32 start;
172 | u8 from_pattern;
173 | } es_note_t;
174 |
175 | typedef struct {
176 | u8 on;
177 | u8 index;
178 | u16 interval;
179 | } es_event_t;
180 |
181 | typedef struct {
182 | es_event_t e[ES_EVENTS_PER_PATTERN];
183 | u16 interval_ind;
184 | u16 length;
185 | u8 loop;
186 | u8 root_x;
187 | u8 root_y;
188 | u8 edge;
189 | u16 edge_time;
190 | u8 voices;
191 | u8 dir;
192 | u8 linearize;
193 | u8 start;
194 | u8 end;
195 | } es_pattern_t;
196 |
197 | typedef struct {
198 | u8 arp;
199 | u8 p_select;
200 | u8 voices;
201 | u8 octave;
202 | u8 scale;
203 | u8 keymap[256];
204 | es_pattern_t p[16];
205 | u8 glyph[8];
206 | } es_data_t;
207 |
208 | extern es_data_t e;
209 |
210 | typedef struct {
211 | u8 preset;
212 | es_data_t e[GRID_PRESETS];
213 | } es_state_t;
214 |
215 |
216 | void set_mode_grid(void);
217 |
218 | void handler_GridFrontShort(s32 data);
219 | void handler_GridFrontLong(s32 data);
220 | void refresh_preset(void);
221 | void refresh_grid_tuning(void);
222 | void grid_keytimer(void);
223 | void ii_grid(uint8_t* data, uint8_t len);
224 |
225 | void default_kria(void);
226 | void init_kria(void);
227 | void resume_kria(void);
228 | void clock_kria(uint8_t phase);
229 | void clock_kria_track( uint8_t trackNum );
230 | void clock_kria_note(kria_track* track, uint8_t trackNum);
231 | void ii_kria(uint8_t *d, uint8_t l);
232 | void handler_KriaGridKey(s32 data);
233 | void handler_KriaRefresh(s32 data);
234 | void handler_KriaKey(s32 data);
235 | void handler_KriaTr(s32 data);
236 | void handler_KriaTrNormal(s32 data);
237 | void refresh_kria(void);
238 | void refresh_kria_view(kria_view_t* view);
239 | bool refresh_kria_mod(kria_view_t* view);
240 | void refresh_kria_tr(kria_view_t* view);
241 | void refresh_kria_note(kria_view_t* view);
242 | void refresh_kria_oct(kria_view_t* view);
243 | void refresh_kria_dur(kria_view_t* view);
244 | void refresh_kria_rpt(kria_view_t* view);
245 | void refresh_kria_glide(kria_view_t* view);
246 | void refresh_kria_scale(kria_view_t* view);
247 | void refresh_kria_pattern(kria_view_t* view);
248 | void refresh_kria_config(void);
249 |
250 | void default_mp(void);
251 | void init_mp(void);
252 | void resume_mp(void);
253 | void clock_mp(uint8_t phase);
254 | void ii_mp(uint8_t *d, uint8_t l);
255 | void handler_MPGridKey(s32 data);
256 | void handler_MPRefresh(s32 data);
257 | void handler_MPKey(s32 data);
258 | void handler_MPTr(s32 data);
259 | void handler_MPTrNormal(s32 data);
260 | void refresh_mp(void);
261 | void refresh_mp_config(void);
262 | void refresh_clock(void);
263 |
264 | void default_es(void);
265 | void init_es(void);
266 | void resume_es(void);
267 | void handler_ESGridKey(s32 data);
268 | void handler_ESRefresh(s32 data);
269 | void handler_ESKey(s32 data);
270 | void handler_ESTr(s32 data);
271 | void handler_ESTrNormal(s32 data);
272 | void refresh_es(void);
273 | void ii_es(uint8_t *d, uint8_t l);
274 |
--------------------------------------------------------------------------------
/src/ansible_ii_leader.c:
--------------------------------------------------------------------------------
1 | #include "dac.h"
2 | #include "i2c.h"
3 | #include "ii.h"
4 | #include "ansible_ii_leader.h"
5 | #include "main.h"
6 | #include "music.h"
7 |
8 | static uint16_t aux_to_vel(uint16_t aux) {
9 | // map from 1-320 range of duration param to V 2 - V 5 for velocity control
10 | return aux * 41 + 3264;
11 | }
12 |
13 | static void ii_init_jf(i2c_follower_t* follower, uint8_t track, uint8_t state) {
14 | uint8_t d[4] = { 0 };
15 |
16 | if (!state)
17 | {
18 | // set velocity to max to restore normal functionality
19 | d[0] = JF_VTR;
20 | d[1] = 0;
21 | d[2] = 16384 >> 8;
22 | d[3] = 16834 & 0xFF;
23 | i2c_leader_tx(follower->addr, d, 3);
24 |
25 | // clear all triggers to avoid hanging notes in SUSTAIN
26 | d[0] = JF_TR;
27 | d[1] = 0;
28 | d[2] = 0;
29 | i2c_leader_tx(follower->addr, d, 3);
30 | }
31 |
32 | d[0] = JF_MODE;
33 | d[1] = state;
34 | i2c_leader_tx(follower->addr, d, 2);
35 | }
36 |
37 | static void ii_tr_jf(i2c_follower_t* follower, uint8_t track, uint8_t state) {
38 | uint8_t d[6] = { 0 };
39 | uint8_t l = 0;
40 | uint16_t pitch = ET[outputs[track].semitones];
41 | if (state) {
42 | // map from 1-320 range of duration param to V 2 - V 5 for velocity control
43 | uint16_t vel = aux_to_vel(aux_param[0][track]);
44 | switch (follower->active_mode) {
45 | case 0: { // polyphonically allocated
46 | d[0] = JF_NOTE;
47 | d[1] = pitch >> 8;
48 | d[2] = pitch & 0xFF;
49 | d[3] = vel >> 8;
50 | d[4] = vel & 0xFF;
51 | l = 5;
52 | break;
53 | }
54 | case 1: { // tracks to first 4 voices
55 | d[0] = JF_VOX;
56 | d[1] = track + 1;
57 | d[2] = pitch >> 8;
58 | d[3] = pitch & 0xFF;
59 | d[4] = vel >> 8;
60 | d[5] = vel & 0xFF;
61 | l = 6;
62 | break;
63 | }
64 | case 2: { // envelopes
65 | d[0] = JF_VTR;
66 | d[1] = track + 1;
67 | d[2] = vel >> 8;
68 | d[3] = vel & 0xFF;
69 | l = 4;
70 | break;
71 | }
72 | default: {
73 | return;
74 | }
75 | }
76 | }
77 | else {
78 | if (follower->active_mode == 0) {
79 | d[0] = JF_NOTE;
80 | d[1] = pitch >> 8;
81 | d[2] = pitch & 0xFF;
82 | d[3] = 0;
83 | d[4] = 0;
84 | l = 5;
85 | }
86 | else
87 | {
88 | d[0] = JF_TR;
89 | d[1] = track + 1;
90 | d[2] = 0;
91 | l = 3;
92 | }
93 | }
94 | if (l > 0) {
95 | i2c_leader_tx(follower->addr, d, l);
96 | }
97 | }
98 |
99 | static void ii_mute_jf(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
100 | uint8_t d[3] = { 0 };
101 |
102 | // clear all triggers to avoid hanging notes in SUSTAIN
103 | d[0] = JF_TR;
104 | d[1] = 0;
105 | d[2] = 0;
106 | i2c_leader_tx(follower->addr, d, 3);
107 | }
108 |
109 | static void ii_mode_jf(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
110 | uint8_t d[4] = { 0 };
111 |
112 | if (mode > follower->ops->mode_ct) return;
113 | follower->active_mode = mode;
114 | if (mode == 2) {
115 | d[0] = JF_MODE;
116 | d[1] = 0;
117 | i2c_leader_tx(follower->addr, d, 2);
118 |
119 | // clear all triggers to avoid hanging notes in SUSTAIN
120 | d[0] = JF_TR;
121 | d[1] = 0;
122 | d[2] = 0;
123 | d[3] = 0;
124 | i2c_leader_tx(follower->addr, d, 3);
125 | }
126 | else
127 | {
128 | d[0] = JF_MODE;
129 | d[1] = 1;
130 | i2c_leader_tx(follower->addr, d, 2);
131 | }
132 | }
133 |
134 | static void ii_octave_jf(i2c_follower_t* follower, uint8_t track, int8_t octave) {
135 | int16_t shift;
136 | if (octave > 0) {
137 | shift = ET[12*octave];
138 | }
139 | else if (octave < 0) {
140 | shift = -(ET[12*(-octave)]);
141 | }
142 | else {
143 | shift = 0;
144 | }
145 |
146 | uint8_t d[] = { JF_SHIFT, shift >> 8, shift & 0xFF };
147 | i2c_leader_tx(follower->addr, d, 3);
148 | }
149 |
150 | static void ii_init_txo(i2c_follower_t* follower, uint8_t track, uint8_t state) {
151 | uint8_t d[4] = { 0 };
152 |
153 | if (state == 0) {
154 | d[0] = 0x60; // TO_ENV_ACT
155 | d[1] = track;
156 | d[2] = 0;
157 | d[3] = 0;
158 | i2c_leader_tx(follower->addr, d, 4);
159 |
160 | d[0] = 0x40; // TO_OSC
161 | d[1] = track;
162 | d[2] = 0;
163 | d[3] = 0;
164 | i2c_leader_tx(follower->addr, d, 4);
165 |
166 | d[0] = 0x10; // TO_CV
167 | d[1] = track;
168 | d[2] = 0;
169 | d[3] = 0;
170 | i2c_leader_tx(follower->addr, d, 4);
171 | }
172 | }
173 |
174 | static void ii_mode_txo(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
175 | uint8_t d[4] = { 0 };
176 |
177 | if (mode > follower->ops->mode_ct) return;
178 | follower->active_mode = mode;
179 |
180 | switch (mode) {
181 | case 0: { // enveloped oscillators
182 | d[0] = 0x60; // TO_ENV_ACT
183 | d[1] = track;
184 | d[2] = 0;
185 | d[3] = 1;
186 | i2c_leader_tx(follower->addr, d, 4);
187 |
188 | d[0] = 0x15; // TO_CV_OFF
189 | d[1] = track;
190 | d[2] = 0;
191 | d[3] = 0;
192 | i2c_leader_tx(follower->addr, d, 4);
193 |
194 | d[0] = 0x10; // TO_CV
195 | d[1] = track;
196 | d[2] = 8192 >> 8;
197 | d[3] = 8192 & 0xFF;
198 | i2c_leader_tx(follower->addr, d, 4);
199 | break;
200 | }
201 | case 1: { // gate/cv
202 | d[0] = 0x60; // TO_ENV_ACT
203 | d[1] = track;
204 | d[2] = 0;
205 | d[3] = 0;
206 | i2c_leader_tx(follower->addr, d, 4);
207 |
208 | d[0] = 0x40; // TO_OSC
209 | d[1] = track;
210 | d[2] = 0;
211 | d[3] = 0;
212 | i2c_leader_tx(follower->addr, d, 4);
213 |
214 | d[0] = 0x10; // TO_CV
215 | d[1] = track;
216 | d[2] = 0;
217 | d[3] = 0;
218 | i2c_leader_tx(follower->addr, d, 4);
219 | break;
220 | }
221 | default: return;
222 | }
223 | }
224 |
225 | static void ii_octave_txo(i2c_follower_t* follower, uint8_t track, int8_t octave) {
226 | int16_t shift;
227 | switch (follower->active_mode) {
228 | case 0: { // enveloped oscillator, pitch is calculated from oct
229 | break;
230 | }
231 | case 1: { // gate / cv
232 | if (octave > 0) {
233 | shift = ET[12*octave];
234 | }
235 | else if (octave < 0) {
236 | shift = -ET[12*(-octave)];
237 | }
238 | else {
239 | shift = 0;
240 | }
241 | uint8_t d[] = {
242 | 0x15, // TO_CV_OFF
243 | 0,
244 | shift >> 8,
245 | shift & 0xFF,
246 | };
247 | for (uint8_t i = 0; i < 4; i++) {
248 | d[1] = i;
249 | i2c_leader_tx(follower->addr, d, 4);
250 | }
251 | break;
252 | }
253 | default: return;
254 | }
255 | }
256 |
257 | static void ii_tr_txo(i2c_follower_t* follower, uint8_t track, uint8_t state) {
258 | uint8_t d[4] = { 0 };
259 |
260 | switch (follower->active_mode) {
261 | case 0: { // enveloped oscillator
262 | d[0] = 0x6D; // TO_ENV
263 | d[1] = track;
264 | d[2] = 0;
265 | d[3] = state;
266 | i2c_leader_tx(follower->addr, d, 4);
267 | break;
268 | }
269 | case 1: { // gate/cv
270 | d[0] = 0x00; // TO_TR
271 | d[1] = track;
272 | d[2] = 0;
273 | d[3] = state;
274 | i2c_leader_tx(follower->addr, d, 4);
275 | break;
276 | }
277 | default: return;
278 | }
279 | }
280 |
281 | static void ii_mute_txo(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
282 | for (uint8_t i = 0; i < 4; i++) {
283 | ii_tr_txo(follower, i, 0);
284 | }
285 | }
286 |
287 | static void ii_cv_txo(i2c_follower_t* follower, uint8_t track, uint16_t dac_value) {
288 | uint8_t d[4] = { 0 };
289 |
290 | switch (follower->active_mode) {
291 | case 0: { // enveloped oscillator
292 | dac_value = (int)dac_value + (int)ET[12*(4+follower->oct)];
293 | d[0] = 0x40; // TO_OSC
294 | d[1] = track;
295 | d[2] = dac_value >> 8;
296 | d[3] = dac_value & 0xFF;
297 | i2c_leader_tx(follower->addr, d, 4);
298 | break;
299 | }
300 | case 1: { // gate/cv
301 | d[0] = 0x10; // TO_CV
302 | d[1] = track;
303 | d[2] = dac_value >> 8;
304 | d[3] = dac_value & 0xFF;
305 | i2c_leader_tx(follower->addr, d, 4);
306 | break;
307 | }
308 | default: return;
309 | }
310 | }
311 |
312 | static void ii_slew_txo(i2c_follower_t* follower, uint8_t track, uint16_t slew) {
313 | uint8_t d[4] = { 0 };
314 |
315 | switch (follower->active_mode) {
316 | case 0: { // oscillator
317 | d[0] = 0x4F; // TO_OSC_SLEW
318 | d[1] = track;
319 | d[2] = slew >> 8;
320 | d[3] = slew & 0xFF;
321 | i2c_leader_tx(follower->addr, d, 4);
322 | break;
323 | }
324 | case 1: { // gate/cv
325 | d[0] = 0x12; // TO_CV_SLEW
326 | d[1] = track;
327 | d[2] = slew >> 8;
328 | d[3] = slew & 0xFF;
329 | i2c_leader_tx(follower->addr, d, 4);
330 | break;
331 | }
332 | default: return;
333 | }
334 | }
335 |
336 | static void ii_mode_disting_ex(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
337 | if (mode > follower->ops->mode_ct) return;
338 | follower->active_mode = mode;
339 | }
340 |
341 | static void ii_tr_disting_ex(i2c_follower_t* follower, uint8_t track, uint8_t state) {
342 | uint8_t d[4] = { 0 };
343 | u16 note = outputs[track].semitones + 12 * (4 + follower->oct);
344 |
345 | switch (follower->active_mode) {
346 | case 0: // SD Multisample / SD Triggers allocated voices
347 | if (note < 0) note = 0; else if (note > 127) note = 127;
348 | if (state) {
349 | d[0] = 0x56;
350 | d[1] = note;
351 | i2c_leader_tx(follower->addr, d, 2);
352 | d[0] = 0x55;
353 | d[2] = 0x40;
354 | d[3] = 0;
355 | i2c_leader_tx(follower->addr, d, 4);
356 | } else {
357 | d[0] = 0x56;
358 | d[1] = note;
359 | i2c_leader_tx(follower->addr, d, 2);
360 | }
361 | break;
362 |
363 | case 1: // SD Multisample / SD Triggers fixed voices
364 | if (state) {
365 | d[0] = 0x52;
366 | d[1] = track;
367 | d[2] = 0x40;
368 | d[3] = 0;
369 | i2c_leader_tx(follower->addr, d, 4);
370 | } else {
371 | d[0] = 0x53;
372 | d[1] = track;
373 | i2c_leader_tx(follower->addr, d, 2);
374 | }
375 | break;
376 |
377 | case 2: // MIDI channel 1
378 | if (note < 0 || note > 127) return;
379 | if (state) {
380 | d[0] = 0x4F;
381 | d[1] = 0x90;
382 | d[2] = note;
383 | d[3] = 80;
384 | i2c_leader_tx(follower->addr, d, 4);
385 | } else {
386 | d[0] = 0x4F;
387 | d[1] = 0x80;
388 | d[2] = note;
389 | d[3] = 0;
390 | i2c_leader_tx(follower->addr, d, 4);
391 | }
392 | break;
393 | case 3: // MIDI channels 1-4
394 | if (note < 0 || note > 127) return;
395 | if (state) {
396 | d[0] = 0x4F;
397 | d[1] = 0x90 + track;
398 | d[2] = note;
399 | d[3] = 80;
400 | i2c_leader_tx(follower->addr, d, 4);
401 | } else {
402 | d[0] = 0x4F;
403 | d[1] = 0x80 + track;
404 | d[2] = note;
405 | d[3] = 0;
406 | i2c_leader_tx(follower->addr, d, 4);
407 | }
408 | break;
409 | default: return;
410 | }
411 | }
412 |
413 | static void ii_mute_disting_ex(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
414 | for (uint8_t i = 0; i < 4; i++) {
415 | ii_tr_disting_ex(follower, i, 0);
416 | }
417 |
418 | uint8_t d[1] = { 0x57 };
419 | i2c_leader_tx(follower->addr, d, 1);
420 | }
421 |
422 | static void ii_cv_disting_ex(i2c_follower_t* follower, uint8_t track, uint16_t dac_value) {
423 | uint8_t d[4] = { 0 };
424 |
425 | u16 note = outputs[track].semitones + 12 * (4 + follower->oct);
426 | u16 pitch = ET[note] - ET[36];
427 |
428 | d[2] = pitch >> 8;
429 | d[3] = pitch;
430 |
431 | if (follower->active_mode == 0) {
432 | if (note < 0) note = 0; else if (note > 127) note = 127;
433 | d[0] = 0x54;
434 | d[1] = note;
435 | i2c_leader_tx(follower->addr, d, 4);
436 | } else if (follower->active_mode == 1) {
437 | d[0] = 0x51;
438 | d[1] = track;
439 | i2c_leader_tx(follower->addr, d, 4);
440 | }
441 | }
442 |
443 | static void ii_init_wsyn(i2c_follower_t* follower, uint8_t track, uint8_t state) {
444 | uint8_t d[4] = { 0 };
445 |
446 | if (!state)
447 | {
448 | // clear all triggers to avoid hanging notes in SUSTAIN
449 | d[0] = WS_S_VEL;
450 | d[1] = 0;
451 | d[2] = 0;
452 | d[3] = 0;
453 | i2c_leader_tx(follower->addr, d, 4);
454 | }
455 | else
456 | {
457 | d[0] = WS_S_AR_MODE;
458 | d[1] = 0;
459 | i2c_leader_tx(follower->addr, d, 2);
460 | }
461 | }
462 |
463 | static void ii_tr_wsyn(i2c_follower_t* follower, uint8_t track, uint8_t state) {
464 | uint8_t d[6] = { 0 };
465 | uint8_t l = 0;
466 | uint16_t pitch = ET[outputs[track].semitones + (3 + follower->oct) * 12];
467 | if (state) {
468 | uint16_t vel = aux_to_vel(aux_param[0][track]);
469 | switch (follower->active_mode) {
470 | case 0: { // polyphonically allocated
471 | d[0] = WS_S_NOTE;
472 | d[1] = pitch >> 8;
473 | d[2] = pitch & 0xFF;
474 | d[3] = vel >> 8;
475 | d[4] = vel & 0xFF;
476 | l = 5;
477 | break;
478 | }
479 | case 1: { // tracks to first 4 voices
480 | d[0] = WS_S_VOX;
481 | d[1] = track + 1;
482 | d[2] = pitch >> 8;
483 | d[3] = pitch & 0xFF;
484 | d[4] = vel >> 8;
485 | d[5] = vel & 0xFF;
486 | l = 6;
487 | break;
488 | }
489 | default: {
490 | return;
491 | }
492 | }
493 | }
494 | else {
495 | switch (follower->active_mode) {
496 | case 0: {
497 | d[0] = WS_S_NOTE;
498 | d[1] = pitch >> 8;
499 | d[2] = pitch & 0xFF;
500 | d[3] = 0;
501 | d[4] = 0;
502 | l = 5;
503 | break;
504 | }
505 | case 1: {
506 | d[0] = WS_S_VOX;
507 | d[1] = track + 1;
508 | d[2] = pitch >> 8;
509 | d[3] = pitch & 0xFF;
510 | d[4] = 0;
511 | d[5] = 0;
512 | l = 6;
513 | break;
514 | }
515 | }
516 | }
517 | if (l > 0) {
518 | i2c_leader_tx(follower->addr, d, l);
519 | }
520 | }
521 |
522 | static void ii_mode_wsyn(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
523 | if (mode > follower->ops->mode_ct) return;
524 | follower->active_mode = mode;
525 | }
526 |
527 | static void ii_mute_wsyn(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
528 | uint8_t d[6] = { 0 };
529 |
530 | // clear all triggers to avoid hanging notes in SUSTAIN
531 | d[0] = WS_S_VOX;
532 | d[1] = 0;
533 | d[2] = 0;
534 | d[3] = 0;
535 | d[4] = 0;
536 | d[5] = 0;
537 | i2c_leader_tx(follower->addr, d, 6);
538 | }
539 |
540 | static void ii_cv_wsyn(i2c_follower_t* follower, uint8_t track, uint16_t dac_value) {
541 | uint8_t d[4] = { 0 };
542 | d[0] = WS_S_PITCH;
543 | d[1] = track;
544 | d[2] = dac_value >> 8;
545 | d[3] = dac_value & 0xFF;
546 | i2c_leader_tx(follower->addr, d, 4);
547 | }
548 |
549 | static void ii_mode_crow(i2c_follower_t* follower, uint8_t track, uint8_t mode) {
550 | if (mode > follower->ops->mode_ct) return;
551 | follower->active_mode = mode;
552 | }
553 |
554 | static void ii_tr_crow(i2c_follower_t* follower, uint8_t track, uint8_t state) {
555 | uint8_t d[7];
556 | uint16_t pitch = ET[outputs[track].semitones];
557 | uint16_t vel = state && aux_to_vel(aux_param[0][track]);
558 |
559 | d[0] = 6; // call3
560 | d[1] = 0;
561 | d[2] = track + 1;
562 | d[3] = pitch >> 8;
563 | d[4] = pitch & 0xFF;
564 | d[5] = vel >> 8;
565 | d[6] = vel & 0xFF;
566 | i2c_leader_tx(follower->addr, d, 7);
567 | }
568 |
569 | static void ii_u8_nop(i2c_follower_t* follower, uint8_t track, uint8_t state) {
570 | }
571 |
572 | static void ii_s8_nop(i2c_follower_t* follower, uint8_t track, int8_t state) {
573 | }
574 |
575 | static void ii_u16_nop(i2c_follower_t* follower, uint8_t track, uint16_t dac_value) {
576 | }
577 |
578 | i2c_follower_t followers[I2C_FOLLOWER_COUNT] = {
579 | {
580 | .addr = JF_ADDR,
581 | .active = false,
582 | .track_en = 0xF,
583 | .oct = 0,
584 | .active_mode = 0,
585 |
586 | .ops = &(i2c_ops_t){
587 | .init = ii_init_jf,
588 | .mode = ii_mode_jf,
589 | .tr = ii_tr_jf,
590 | .mute = ii_mute_jf,
591 | .cv = ii_u16_nop,
592 | .octave = ii_octave_jf,
593 | .slew = ii_u16_nop,
594 | .mode_ct = 3,
595 | },
596 | },
597 | {
598 | .addr = TELEXO_0,
599 | .active = false,
600 | .track_en = 0xF,
601 | .oct = 0,
602 | .active_mode = 0,
603 |
604 | .ops = &(i2c_ops_t){
605 | .init = ii_init_txo,
606 | .mode = ii_mode_txo,
607 | .tr = ii_tr_txo,
608 | .mute = ii_mute_txo,
609 | .cv = ii_cv_txo,
610 | .octave = ii_octave_txo,
611 | .slew = ii_slew_txo,
612 | .mode_ct = 2,
613 | },
614 | },
615 | {
616 | .addr = ER301_1,
617 | .active = false,
618 | .track_en = 0xF,
619 | .oct = 0,
620 | .active_mode = 1, // always gate/cv
621 |
622 | .ops = &(i2c_ops_t){
623 | .init = ii_u8_nop,
624 | .mode = ii_u8_nop,
625 | .tr = ii_tr_txo,
626 | .mute = ii_mute_txo,
627 | .cv = ii_cv_txo,
628 | .octave = ii_octave_txo,
629 | .slew = ii_slew_txo,
630 | .mode_ct = 1,
631 | },
632 | },
633 | {
634 | .addr = DISTING_EX_1,
635 | .active = false,
636 | .track_en = 0xF,
637 | .oct = 0,
638 | .active_mode = 0,
639 |
640 | .ops = &(i2c_ops_t){
641 | .init = ii_u8_nop,
642 | .mode = ii_mode_disting_ex,
643 | .tr = ii_tr_disting_ex,
644 | .mute = ii_mute_disting_ex,
645 | .cv = ii_cv_disting_ex,
646 | .octave = ii_s8_nop,
647 | .slew = ii_u16_nop,
648 | .mode_ct = 4,
649 | },
650 | },
651 | {
652 | .addr = WS_S_ADDR,
653 | .active = false,
654 | .track_en = 0xF,
655 | .oct = -2,
656 | .active_mode = 0,
657 |
658 | .ops = &(i2c_ops_t){
659 | .init = ii_init_wsyn,
660 | .mode = ii_mode_wsyn,
661 | .tr = ii_tr_wsyn,
662 | .mute = ii_mute_wsyn,
663 | .cv = ii_cv_wsyn,
664 | .octave = ii_s8_nop,
665 | .slew = ii_u16_nop,
666 |
667 | .mode_ct = 2,
668 | },
669 | },
670 | {
671 | .addr = CROW,
672 | .active = false,
673 | .track_en = 0xF,
674 | .oct = 0,
675 | .active_mode = 0,
676 |
677 | .ops = &(i2c_ops_t){
678 | .init = ii_u8_nop,
679 | .mode = ii_mode_crow,
680 | .tr = ii_tr_crow,
681 | .mute = ii_u8_nop,
682 | .cv = ii_u16_nop,
683 | .octave = ii_s8_nop,
684 | .slew = ii_u16_nop,
685 |
686 | .mode_ct = 1,
687 | },
688 | },
689 | };
690 |
691 | void follower_change_mode(i2c_follower_t* follower, uint8_t param) {
692 | for (int i = 0; i < 4; i++) {
693 | if (follower->track_en & (1 << i)) {
694 | follower->ops->mode(follower, i, param);
695 | }
696 | }
697 | }
698 |
699 | void follower_change_octave(i2c_follower_t* follower, int8_t param) {
700 | for (int i = 0; i < 4; i++) {
701 | if (follower->track_en & (1 << i)) {
702 | follower->ops->octave(follower, i, param);
703 | }
704 | }
705 | }
706 |
--------------------------------------------------------------------------------
/src/ansible_ii_leader.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define I2C_FOLLOWER_COUNT 6
4 |
5 | struct i2c_follower_t;
6 |
7 | typedef void(*ii_u8_cb)(struct i2c_follower_t* follower, uint8_t track, uint8_t param);
8 | typedef void(*ii_s8_cb)(struct i2c_follower_t* follower, uint8_t track, int8_t param);
9 | typedef void(*ii_u16_cb)(struct i2c_follower_t* follower, uint8_t track, uint16_t param);
10 |
11 |
12 | typedef struct i2c_ops_t {
13 | ii_u8_cb init;
14 | ii_u8_cb mode;
15 | ii_u8_cb tr;
16 | ii_u8_cb mute;
17 |
18 | ii_u16_cb cv;
19 | ii_u16_cb slew;
20 | ii_s8_cb octave;
21 |
22 | uint8_t mode_ct;
23 | } i2c_ops_t;
24 |
25 | typedef struct i2c_follower_t {
26 | uint8_t addr;
27 | bool active;
28 | uint8_t track_en;
29 | int8_t oct;
30 | uint8_t active_mode;
31 |
32 | i2c_ops_t* ops;
33 | } i2c_follower_t;
34 |
35 | extern i2c_follower_t followers[I2C_FOLLOWER_COUNT];
36 |
37 | void follower_change_mode(i2c_follower_t* follower, uint8_t param);
38 | void follower_change_octave(i2c_follower_t* follower, int8_t param);
39 |
--------------------------------------------------------------------------------
/src/ansible_midi.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // NB: NOTE_POOL_SIZE and CHORD_MAX_NOTES (in libavr32) need to match
4 | // in order for the as played arp logic to work correctly.
5 | //
6 | // the defines represent the maximum number of notes tracked in legato
7 | // note handling and the maximum number of (input) notes to the arp
8 | // logic respectively.
9 |
10 | // libavr32
11 | #include "arp.h"
12 |
13 | // standard midi modes
14 | typedef enum {
15 | eVoicePoly = 0,
16 | eVoiceMono,
17 | eVoiceMulti,
18 | eVoiceFixed,
19 |
20 | eVoiceMAX
21 | } voicing_mode;
22 |
23 | // note, cc mappings for fixed voice mode
24 | typedef struct {
25 | u8 notes[4];
26 | u8 cc[4];
27 | } fixed_mapping_t;
28 |
29 | // standard mode values saved to nvram
30 | typedef struct {
31 | uint32_t clock_period;
32 | u8 voicing;
33 | fixed_mapping_t fixed;
34 | s16 shift; // tuning/dac offset
35 | s16 slew; // pitch cv slew (ms)
36 | } midi_standard_state_t;
37 |
38 | typedef struct {
39 | u8 fill;
40 | u8 division;
41 | s8 rotation;
42 | u8 gate;
43 | u8 steps;
44 | u8 offset;
45 |
46 | s16 slew;
47 | s16 shift;
48 | } midi_arp_player_state_t;
49 |
50 | // arp mode value saved to nvram
51 | typedef struct {
52 | uint32_t clock_period;
53 | u8 style; // NB: not using arp_style as type because enums have vairable size
54 | bool hold; // if true new notes add to chord if at least one note in chord is still held
55 | midi_arp_player_state_t p[4];
56 | } midi_arp_state_t;
57 |
58 | void set_mode_midi(void);
59 |
60 | void handler_MidiFrontShort(s32 data);
61 | void handler_MidiFrontLong(s32 data);
62 |
63 | void default_midi_standard(void);
64 | void clock_midi_standard(uint8_t phase);
65 | void ii_midi_standard(uint8_t *d, uint8_t l);
66 | void handler_StandardKey(s32 data);
67 | void handler_StandardTr(s32 data);
68 | void handler_StandardTrNormal(s32 data);
69 | void handler_StandardMidiPacket(s32 data);
70 |
71 | void default_midi_arp(void);
72 | void clock_midi_arp(uint8_t phase);
73 | void ii_midi_arp(uint8_t *d, uint8_t l);
74 | void handler_ArpKey(s32 data);
75 | void handler_ArpTr(s32 data);
76 | void handler_ArpTrNormal(s32 data);
77 | void handler_ArpMidiPacket(s32 data);
78 |
--------------------------------------------------------------------------------
/src/ansible_preset_docdef.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "json/serdes.h"
4 |
5 | #define ANSIBLE_FIRMWARE_NAME "ansible"
6 |
7 | json_docdef_t ansible_preset_docdef;
8 |
--------------------------------------------------------------------------------
/src/ansible_tt.c:
--------------------------------------------------------------------------------
1 | #include "print_funcs.h"
2 | #include "flashc.h"
3 |
4 | #include "monome.h"
5 | #include "i2c.h"
6 | #include "init_common.h"
7 | #include "dac.h"
8 | #include "ii.h"
9 |
10 | #include "main.h"
11 | #include "ansible_tt.h"
12 |
13 | uint8_t tr_pol[4];
14 | uint16_t tr_time[4];
15 |
16 | bool input[4];
17 |
18 | void set_mode_tt(void) {
19 | print_dbg("\r\n> mode tt");
20 | app_event_handlers[kEventKey] = &handler_TTKey;
21 | app_event_handlers[kEventTr] = &handler_TTTr;
22 | app_event_handlers[kEventTrNormal] = &handler_TTTrNormal;
23 | clock = &clock_tt;
24 | clock_set(f.tt_state.clock_period);
25 | if (!leader_mode) init_i2c_follower(f.state.i2c_addr);
26 | process_ii = &ii_tt;
27 | update_leds(0);
28 |
29 | clr_tr(TR1);
30 | clr_tr(TR2);
31 | clr_tr(TR3);
32 | clr_tr(TR4);
33 |
34 | dac_set_slew(0,0);
35 | dac_set_slew(1,0);
36 | dac_set_slew(2,0);
37 | dac_set_slew(3,0);
38 | }
39 |
40 | void default_tt() {
41 | flashc_memset32((void*)&(f.tt_state.clock_period), 500, 4, true);
42 | }
43 |
44 | void init_tt() {
45 | for(int i1=0;i1<4;i1++) {
46 | tr_pol[i1] = 1;
47 | tr_time[i1] = 100;
48 | }
49 | }
50 |
51 | void clock_tt(uint8_t phase) {
52 | // static uint16_t d[4];
53 | // static uint16_t cv;
54 | // cv += 0xff;
55 | // cv &= 4095;
56 |
57 | // d[2] = cv;
58 | // d[3] = 4095 - cv;
59 |
60 | // update_dacs(d);
61 |
62 | // if(phase)
63 | // set_tr(TR4);
64 | // else
65 | // clr_tr(TR4);
66 | ;;
67 | }
68 |
69 |
70 | void tr_pulse0(void* o) {
71 | if(tr_pol[0]) clr_tr(TR1);
72 | else set_tr(TR1);
73 | timer_remove( &auxTimer[0]);
74 | }
75 |
76 | void tr_pulse1(void* o) {
77 | if(tr_pol[1]) clr_tr(TR2);
78 | else set_tr(TR2);
79 | timer_remove( &auxTimer[1]);
80 | }
81 |
82 | void tr_pulse2(void* o) {
83 | if(tr_pol[2]) clr_tr(TR3);
84 | else set_tr(TR3);
85 | timer_remove( &auxTimer[2]);
86 | }
87 |
88 | void tr_pulse3(void* o) {
89 | if(tr_pol[3]) clr_tr(TR4);
90 | else set_tr(TR4);
91 | timer_remove( &auxTimer[3]);
92 | }
93 |
94 |
95 | void ii_tt(uint8_t *d, uint8_t l) {
96 | // print_dbg("\r\ni2c:");
97 | // print_dbg_ulong(l);
98 | // print_dbg(" ");
99 | // for(int i=0;i> 8);
126 | ii_tx_queue(tr_time[d[1]] & 0xff);
127 | break;
128 | case II_ANSIBLE_TR_POL:
129 | tr_pol[d[1]] = d[2];
130 | break;
131 | case II_ANSIBLE_TR_POL + II_GET:
132 | ii_tx_queue(tr_pol[d[1]]);
133 | break;
134 | case II_ANSIBLE_TR_PULSE:
135 | switch(d[1]) {
136 | case 0:
137 | if(tr_pol[0]) set_tr(TR1);
138 | else clr_tr(TR1);
139 | timer_add(&auxTimer[0], tr_time[0], &tr_pulse0, NULL );
140 | break;
141 | case 1:
142 | if(tr_pol[1]) set_tr(TR2);
143 | else clr_tr(TR2);
144 | timer_add(&auxTimer[1], tr_time[1], &tr_pulse1, NULL );
145 | break;
146 | case 2:
147 | if(tr_pol[2]) set_tr(TR3);
148 | else clr_tr(TR3);
149 | timer_add(&auxTimer[2], tr_time[2], &tr_pulse2, NULL );
150 | break;
151 | case 3:
152 | if(tr_pol[3]) set_tr(TR4);
153 | else clr_tr(TR4);
154 | timer_add(&auxTimer[3], tr_time[3], &tr_pulse3, NULL );
155 | break;
156 | default: break;
157 | }
158 | break;
159 | case II_ANSIBLE_CV:
160 | dac_set_value(d[1], (d[2] << 8) + d[3]);
161 | break;
162 | case II_ANSIBLE_CV + II_GET:
163 | ii_tx_queue(dac_get_value(d[1]) >> 8);
164 | ii_tx_queue(dac_get_value(d[1]) & 0xff);
165 | break;
166 | case II_ANSIBLE_CV_SLEW:
167 | dac_set_slew(d[1], (d[2] << 8) + d[3]);
168 | break;
169 | case II_ANSIBLE_CV_SLEW + II_GET:
170 | ii_tx_queue(dac_get_slew(d[1]) >> 8);
171 | ii_tx_queue(dac_get_slew(d[1]) & 0xff);
172 | break;
173 | case II_ANSIBLE_CV_OFF:
174 | dac_set_off(d[1], (d[2] << 8) + d[3]);
175 | break;
176 | case II_ANSIBLE_CV_OFF + II_GET:
177 | ii_tx_queue(dac_get_off(d[1]) >> 8);
178 | ii_tx_queue(dac_get_off(d[1]) & 0xff);
179 | break;
180 | case II_ANSIBLE_CV_SET:
181 | dac_set_value_noslew(d[1], (d[2] << 8) + d[3]);
182 | break;
183 | case II_ANSIBLE_INPUT + II_GET:
184 | ii_tx_queue(input[d[1]]);
185 | break;
186 | default:
187 | ii_ansible(d, l);
188 | break;
189 | }
190 | }
191 | }
192 |
193 |
194 | void handler_TTKey(s32 data) {
195 | // print_dbg("\r\n> TT key");
196 | // print_dbg_ulong(data);
197 |
198 | switch(data) {
199 | case 0:
200 | input[2] = 0;
201 | break;
202 | case 1:
203 | input[2] = 1;
204 | break;
205 | case 2:
206 | input[3] = 0;
207 | break;
208 | case 3:
209 | input[3] = 1;
210 | break;
211 | default:
212 | break;
213 | }
214 |
215 | }
216 |
217 | void handler_TTTr(s32 data) {
218 | // print_dbg("\r\n> TT tr");
219 | // print_dbg_ulong(data);
220 |
221 | switch(data) {
222 | case 0:
223 | input[0] = 0;
224 | break;
225 | case 1:
226 | input[0] = 1;
227 | break;
228 | case 2:
229 | input[1] = 0;
230 | break;
231 | case 3:
232 | input[1] = 1;
233 | break;
234 | default:
235 | break;
236 | }
237 | }
238 |
239 | void handler_TTTrNormal(s32 data) {
240 | // print_dbg("\r\n> TT tr normal ");
241 | // print_dbg_ulong(data);
242 | }
243 |
--------------------------------------------------------------------------------
/src/ansible_tt.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | typedef struct {
4 | uint32_t clock_period;
5 | uint16_t tr_time[4];
6 | uint16_t cv_slew[4];
7 | } tt_state_t;
8 |
9 | void set_mode_tt(void);
10 |
11 | void default_tt(void);
12 | void init_tt(void);
13 | void clock_tt(uint8_t phase);
14 | void ii_tt(uint8_t *d, uint8_t l);
15 |
16 |
17 | void handler_TTKey(s32 data);
18 | void handler_TTTr(s32 data);
19 | void handler_TTTrNormal(s32 data);
20 |
21 |
22 | void tr_pulse0(void* o);
23 | void tr_pulse1(void* o);
24 | void tr_pulse2(void* o);
25 | void tr_pulse3(void* o);
--------------------------------------------------------------------------------
/src/ansible_usb_disk.c:
--------------------------------------------------------------------------------
1 | #include "monome.h"
2 | #include "init_common.h"
3 | #include "main.h"
4 | #include "print_funcs.h"
5 |
6 | #include "ansible_usb_disk.h"
7 | #include "ansible_preset_docdef.h"
8 |
9 | #include "events.h"
10 | #include "flashc.h"
11 | #include "fat.h"
12 | #include "file.h"
13 | #include "fs_com.h"
14 | #include "json/encoding.h"
15 | #include "json/serdes.h"
16 | #include "navigation.h"
17 |
18 | #include "uhi_msc.h"
19 | #include "uhi_msc_mem.h"
20 |
21 | #define DEBUG_ANSIBLE_USB_DISK 0
22 | #define DISK_BLINK_INTERVAL 250
23 |
24 | static void handler_UsbDiskKey(int32_t data);
25 | static void handler_UsbDiskFront(int32_t data);
26 |
27 | static bool usb_disk_mount_drive(void);
28 | static bool usb_disk_backup_binary(FS_STRING fname);
29 | static bool usb_disk_restore_backup(FS_STRING fname);
30 | static bool usb_disk_load_flash(FS_STRING fname);
31 | static bool usb_disk_save_flash(FS_STRING fname);
32 | static void flush(void);
33 | static void blink_read(void* o);
34 | static void blink_write(void* o);
35 |
36 | static char ansible_usb_disk_textbuf[ANSIBLE_USBDISK_TXTBUF_LEN] = { 0 };
37 | static uint8_t usb_disk_buffer[ANSIBLE_USBDISK_BLOCKSIZE] = { 0 };
38 | static jsmntok_t ansible_usb_disk_tokbuf[ANSIBLE_USBDISK_TOKBUF_LEN];
39 |
40 | static volatile bool usb_disk_locked = false;
41 |
42 | static bool usb_disk_lock(void) {
43 | if (!usb_disk_locked) {
44 | usb_disk_locked = true;
45 | print_dbg("\r\n\r\n> usb disk locked");
46 | return true;
47 | }
48 | return false;
49 | }
50 |
51 | static void usb_disk_unlock(void) {
52 | usb_disk_locked = false;
53 | print_dbg("\r\n> usb disk unlocked\r\n");
54 | }
55 |
56 | static volatile bool load_armed = false, save_armed = false;
57 | static bool blink = false;
58 |
59 | static void handler_UsbDiskKey(int32_t data) {
60 | bool success;
61 |
62 | switch (data) {
63 | case 0:
64 | break;
65 | case 1:
66 | // key 1 - load
67 | if (usb_disk_lock()) {
68 | save_armed = false;
69 | if (!load_armed) {
70 | update_leds(1);
71 | load_armed = true;
72 | usb_disk_unlock();
73 | return;
74 | }
75 | load_armed = false;
76 | blink = false;
77 | success = false;
78 | timer_add(&auxTimer[0], DISK_BLINK_INTERVAL, &blink_read, NULL);
79 |
80 | if (usb_disk_enter()) {
81 | if (usb_disk_backup_binary(ANSIBLE_BACKUP_FILE)) {
82 | if (usb_disk_load_flash(ANSIBLE_PRESET_FILE)) {
83 | success = true;
84 | } else {
85 | usb_disk_restore_backup(ANSIBLE_BACKUP_FILE);
86 | }
87 | }
88 | }
89 | usb_disk_exit();
90 |
91 | usb_disk_unlock();
92 | timer_remove(&auxTimer[0]);
93 | update_leds(0);
94 | if (success) {
95 | flash_unfresh();
96 | load_flash_state();
97 | } else {
98 | print_dbg("\r\n!! filesystem error code: ");
99 | print_dbg_hex(fs_g_status - FAIL);
100 | update_leds(3);
101 | }
102 | }
103 | break;
104 | case 3:
105 | // key 2 - save
106 | if (usb_disk_lock()) {
107 | load_armed = false;
108 | if (!save_armed) {
109 | update_leds(2);
110 | save_armed = true;
111 | usb_disk_unlock();
112 | return;
113 | }
114 | save_armed = false;
115 | blink = false;
116 | success = false;
117 | timer_add(&auxTimer[0], DISK_BLINK_INTERVAL, &blink_write, NULL);
118 |
119 | if (usb_disk_enter()) {
120 | success = usb_disk_save_flash(ANSIBLE_PRESET_FILE);
121 | }
122 | usb_disk_exit();
123 |
124 | usb_disk_unlock();
125 | timer_remove(&auxTimer[0]);
126 | update_leds(0);
127 | if (!success) {
128 | print_dbg("\r\n!! filesystem error code: ");
129 | print_dbg_hex(fs_g_status - FAIL);
130 | update_leds(3);
131 | }
132 | }
133 | break;
134 | default:
135 | break;
136 | }
137 | }
138 |
139 | static void handler_UsbDiskFront(s32 data) {
140 | if (usb_disk_lock()) {
141 | load_armed = false;
142 | save_armed = false;
143 | update_leds(0);
144 | usb_disk_unlock();
145 | }
146 | }
147 |
148 | static void blink_read(void* o) {
149 | update_leds(1 * blink);
150 | blink = !blink;
151 | }
152 |
153 | static void blink_write(void* o) {
154 | update_leds(2 * blink);
155 | blink = !blink;
156 | }
157 |
158 | void set_mode_usb_disk(void) {
159 | clock = &clock_null;
160 | update_leds(0);
161 | app_event_handlers[kEventKey] = &handler_UsbDiskKey;
162 | app_event_handlers[kEventFront] = &handler_UsbDiskFront;
163 | }
164 |
165 | bool usb_disk_enter() {
166 | nav_reset();
167 | for (uint8_t i = 0; i < FS_NB_NAVIGATOR; i++) {
168 | if (nav_select(i)) {
169 | if (usb_disk_mount_drive()) {
170 | print_dbg("\r\nmounted nav id ");
171 | print_dbg_hex(i);
172 | return true;
173 | }
174 | print_dbg("\r\n!! could not mount nav id ");
175 | print_dbg_hex(i);
176 | }
177 | }
178 | print_dbg("\r\n!! no nav id worked");
179 | usb_disk_exit();
180 | return false;
181 | }
182 |
183 | void usb_disk_exit() {
184 | nav_filelist_reset();
185 | nav_exit();
186 | }
187 |
188 | void usb_disk_skip_apps(bool skip) {
189 | json_docdef_t* apps = json_docdef_find_key(&ansible_preset_docdef, "apps");
190 | if (apps == NULL) return;
191 | json_read_object_params_t* params = (json_read_object_params_t*)apps->params;
192 | for (int i = 0; i < params->docdef_ct; i++) {
193 | params->docdefs[i].skip = skip;
194 | }
195 | }
196 |
197 | void usb_disk_select_app(ansible_mode_t mode) {
198 | json_docdef_t* app;
199 | json_docdef_t* apps = json_docdef_find_key(&ansible_preset_docdef, "apps");
200 | if (apps == NULL) return;
201 | switch (mode) {
202 | case mArcLevels:
203 | usb_disk_skip_apps(true);
204 | app = json_docdef_find_key(apps, "levels");
205 | if (app == NULL) return;
206 | app->skip = false;
207 | break;
208 | case mArcCycles:
209 | usb_disk_skip_apps(true);
210 | app = json_docdef_find_key(apps, "cycles");
211 | if (app == NULL) return;
212 | app->skip = false;
213 | break;
214 | case mGridKria:
215 | usb_disk_skip_apps(true);
216 | app = json_docdef_find_key(apps, "kria");
217 | if (app == NULL) return;
218 | app->skip = false;
219 | break;
220 | case mGridMP:
221 | usb_disk_skip_apps(true);
222 | app = json_docdef_find_key(apps, "mp");
223 | if (app == NULL) return;
224 | app->skip = false;
225 | break;
226 | // case mGridES:
227 | case mMidiStandard:
228 | usb_disk_skip_apps(true);
229 | app = json_docdef_find_key(apps, "midi_standard");
230 | if (app == NULL) return;
231 | app->skip = false;
232 | break;
233 | case mMidiArp:
234 | usb_disk_skip_apps(true);
235 | app = json_docdef_find_key(apps, "midi_arp");
236 | if (app == NULL) return;
237 | app->skip = false;
238 | break;
239 | case mTT:
240 | usb_disk_skip_apps(true);
241 | app = json_docdef_find_key(apps, "tt");
242 | if (app == NULL) return;
243 | app->skip = false;
244 | break;
245 | default: {
246 | usb_disk_skip_apps(false);
247 | break;
248 | }
249 | }
250 | }
251 |
252 | size_t gets_chunks(char* dst, size_t len) {
253 | size_t read = 0;
254 | uint16_t count, chunk;
255 |
256 | do {
257 | chunk = min(len - read, ANSIBLE_USBDISK_BLOCKSIZE);
258 | count = file_read_buf((uint8_t*)dst + read, chunk);
259 | read += count;
260 | } while (read < len && count > 0);
261 | return read;
262 | }
263 |
264 | static void copy_chunks(char* dst, const char* src, size_t len) {
265 | size_t read = 0;
266 | uint16_t chunk;
267 |
268 | do {
269 | chunk = min(len - read, ANSIBLE_FLASH_BLOCKSIZE);
270 |
271 | #if DEBUG_ANSIBLE_USB_DISK
272 | print_dbg("\r\nsave ");
273 | print_dbg_hex(chunk);
274 | print_dbg(" at ");
275 | print_dbg_hex(src + read);
276 | print_dbg(" to flash @ ");
277 | print_dbg_hex(dst + read);
278 | #endif
279 |
280 | flashc_memcpy(dst + read, src + read, chunk, true);
281 | read += chunk;
282 | } while (read < len);
283 | }
284 |
285 | static uint16_t buf_pos = 0;
286 | size_t total_written = 0;
287 |
288 | static void flush(void) {
289 | #if DEBUG_ANSIBLE_USB_DISK
290 | print_dbg("\r\n\r\nflush ");
291 | print_dbg_hex(buf_pos);
292 | print_dbg(" bytes to disk = \r\n");
293 | for (size_t i = 0; i < buf_pos; i++) {
294 | print_dbg_char(usb_disk_buffer[i]);
295 | }
296 | print_dbg("\r\n");
297 | #endif
298 |
299 | file_write_buf(usb_disk_buffer, buf_pos);
300 | file_flush();
301 | total_written += buf_pos;
302 | buf_pos = 0;
303 | }
304 |
305 | void puts_buffered(const char* src, size_t len) {
306 | uint16_t chunk;
307 |
308 | #if DEBUG_ANSIBLE_USB_DISK
309 | print_dbg("\r\nask to write ");
310 | print_dbg_hex(len);
311 | print_dbg(" = ");
312 | for (size_t i = 0; i < len; i++) {
313 | print_dbg_char(src[i]);
314 | }
315 | #endif
316 |
317 | for (size_t written = 0; written < len; written += chunk) {
318 | if (buf_pos >= sizeof(usb_disk_buffer)) {
319 | flush();
320 | }
321 | chunk = min(len - written, sizeof(usb_disk_buffer) - buf_pos);
322 | memcpy(usb_disk_buffer + buf_pos, src + written, chunk);
323 | buf_pos += chunk;
324 | }
325 | }
326 |
327 | static bool usb_disk_mount_drive(void) {
328 | if (uhi_msc_is_available()) {
329 | for (int i = 0; i < uhi_msc_get_lun(); i++) {
330 | if (nav_drive_set(i)) {
331 | if (nav_partition_mount()) {
332 | return true;
333 | }
334 | print_dbg("\r\n!! could not mount partition");
335 | }
336 | }
337 | print_dbg("\r\n!! drive mount failed");
338 | } else {
339 | print_dbg("\r\n!! msc unavailable for mount");
340 | }
341 | return false;
342 | }
343 |
344 | static bool usb_disk_backup_binary(FS_STRING fname) {
345 | print_dbg("\r\n> making binary backup");
346 | if (!nav_file_create(fname)) {
347 | if (fs_g_status != FS_ERR_FILE_EXIST) {
348 | print_dbg("\r\n!! could not create backup file");
349 | return false;
350 | }
351 | }
352 | if (!file_open(FOPEN_MODE_W)) {
353 | print_dbg("\r\n!! could not open binary backup for write");
354 | return false;
355 | }
356 | puts_buffered((char*)&f, sizeof(nvram_data_t));
357 | flush();
358 | file_flush();
359 | file_close();
360 | print_dbg("\r\n> binary backup done");
361 | return true;
362 | }
363 |
364 | static bool usb_disk_restore_backup(FS_STRING fname) {
365 | print_dbg("\r\n> restoring binary backup");
366 | if (!nav_setcwd(fname, true, true)) {
367 | print_dbg("\r\n!! could not find binary backup");
368 | return false;
369 | }
370 | if (!file_open(FOPEN_MODE_R)) {
371 | print_dbg("\r\n!! could not open binary backup for read");
372 | return false;
373 | }
374 | size_t read = 0;
375 | uint16_t chunk;
376 | do {
377 | chunk = min(sizeof(nvram_data_t) - read, ANSIBLE_USBDISK_TXTBUF_LEN);
378 | file_read_buf((uint8_t*)ansible_usb_disk_textbuf, chunk);
379 | flashc_memcpy((uint8_t*)&f + read, ansible_usb_disk_textbuf, chunk, false);
380 | read += chunk;
381 | } while (read < sizeof(nvram_data_t));
382 | file_close();
383 | return true;
384 | }
385 |
386 | static bool usb_disk_load_flash(FS_STRING fname) {
387 | print_dbg("\r\n> starting usb disk load");
388 | if (!nav_setcwd(fname, true, false)) {
389 | print_dbg("\r\n!! could not find JSON file");
390 | return false;
391 | }
392 | if (!file_open(FOPEN_MODE_R)) {
393 | print_dbg("\r\n!! could not open JSON file for read");
394 | return false;
395 | }
396 | ii_follower_pause();
397 | json_read_result_t result = json_read(
398 | gets_chunks,
399 | copy_chunks,
400 | (void*)&f, &ansible_preset_docdef,
401 | ansible_usb_disk_textbuf, ANSIBLE_USBDISK_TXTBUF_LEN,
402 | ansible_usb_disk_tokbuf, ANSIBLE_USBDISK_TOKBUF_LEN);
403 | file_close();
404 | ii_follower_resume();
405 |
406 | switch (result) {
407 | case JSON_READ_OK:
408 | print_dbg("\r\n> disk load successful");
409 | break;
410 | case JSON_READ_MALFORMED:
411 | print_dbg("\r\n> disk backup malformed");
412 | break;
413 | default:
414 | print_dbg("\r\n> reached invalid state");
415 | break;
416 | }
417 | print_dbg("\r\n> usb disk load done");
418 |
419 | return result == JSON_READ_OK;
420 | }
421 |
422 | static bool usb_disk_save_flash(FS_STRING fname) {
423 | print_dbg("\r\n> writing flash to disk");
424 | if (!nav_file_create(fname)) {
425 | if (fs_g_status != FS_ERR_FILE_EXIST) {
426 | print_dbg("\r\n!! could not create JSON file: ");
427 | print_dbg_hex(fs_g_status);
428 | return false;
429 | }
430 | }
431 | if (!file_open(FOPEN_MODE_W)) {
432 | print_dbg("\r\n!! could not open JSON file for write");
433 | return false;
434 | }
435 | total_written = 0;
436 | json_write_result_t result = json_write(
437 | puts_buffered,
438 | (void*)&f, &ansible_preset_docdef);
439 | flush();
440 | file_flush();
441 | file_close();
442 |
443 | print_dbg("\r\n> flash write complete: ");
444 | print_dbg_hex(total_written);
445 | print_dbg(" bytes total");
446 |
447 | if (result != JSON_WRITE_OK) {
448 | print_dbg("\r\n!! flash write error");
449 | }
450 |
451 | return result == JSON_WRITE_OK;
452 | }
453 |
--------------------------------------------------------------------------------
/src/ansible_usb_disk.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ansible_usb_disk.h"
4 |
5 | #include "fs_com.h"
6 |
7 | #define ANSIBLE_BACKUP_FILE ((FS_STRING)"ansible-backup.bin")
8 | #define ANSIBLE_PRESET_FILE ((FS_STRING)"ansible-preset.json")
9 | #define ANSIBLE_USBDISK_TXTBUF_LEN 64
10 | #define ANSIBLE_USBDISK_TOKBUF_LEN 12
11 | #define ANSIBLE_USBDISK_BLOCKSIZE 1024
12 | #define ANSIBLE_FLASH_BLOCKSIZE (1 << 14)
13 |
14 | void set_mode_usb_disk(void);
15 | bool usb_disk_enter(void);
16 | void usb_disk_exit(void);
17 | void usb_disk_skip_apps(bool skip);
18 | void usb_disk_select_app(ansible_mode_t mode);
19 |
20 | size_t gets_chunks(char* dst, size_t len);
21 | void puts_buffered(const char* src, size_t len);
22 |
--------------------------------------------------------------------------------
/src/config.mk:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2009-2010 Atmel Corporation. All rights reserved.
3 | #
4 | # \asf_license_start
5 | #
6 | # \page License
7 | #
8 | # Redistribution and use in source and binary forms, with or without
9 | # modification, are permitted provided that the following conditions are met:
10 | #
11 | # 1. Redistributions of source code must retain the above copyright notice,
12 | # this list of conditions and the following disclaimer.
13 | #
14 | # 2. Redistributions in binary form must reproduce the above copyright notice,
15 | # this list of conditions and the following disclaimer in the documentation
16 | # and/or other materials provided with the distribution.
17 | #
18 | # 3. The name of Atmel may not be used to endorse or promote products derived
19 | # from this software without specific prior written permission.
20 | #
21 | # 4. This software may only be redistributed and used in connection with an
22 | # Atmel microcontroller product.
23 | #
24 | # THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
25 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
27 | # EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
28 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 | # POSSIBILITY OF SUCH DAMAGE.
35 | #
36 | # \asf_license_stop
37 |
38 |
39 | # project name
40 | THIS = ansible
41 |
42 | # Path to top level ASF directory relative to this project directory.
43 | PRJ_PATH = ../libavr32/asf
44 |
45 | # Target CPU architecture: ap, ucr1, ucr2 or ucr3
46 | #ARCH = ucr1
47 | ARCH = ucr2
48 |
49 | # Target part: none, ap7xxx or uc3xxxxx
50 | # PART = uc3b064
51 | # PART = uc3b0256
52 | PART = uc3b0512
53 |
54 | # Target device flash memory details (used by the avr32program programming
55 | # tool: [cfi|internal]@address
56 | FLASH = internal@0x80000000
57 |
58 | # Clock source to use when programming; xtal, extclk or int
59 | PROG_CLOCK = int
60 |
61 | # Application target name. Given with suffix .a for library and .elf for a
62 | # standalone application.
63 | TARGET = $(THIS).elf
64 |
65 | # List of C source files.
66 | CSRCS = \
67 | ../src/main.c \
68 | ../src/ansible_grid.c \
69 | ../src/ansible_arc.c \
70 | ../src/ansible_midi.c \
71 | ../src/ansible_tt.c \
72 | ../src/ansible_usb_disk.c \
73 | ../src/ansible_preset_docdef.c \
74 | ../src/ansible_ii_leader.c \
75 | ../src/gitversion.c \
76 | ../libavr32/src/adc.c \
77 | ../libavr32/src/arp.c \
78 | ../libavr32/src/dac.c \
79 | ../libavr32/src/euclidean/data.c \
80 | ../libavr32/src/euclidean/euclidean.c \
81 | ../libavr32/src/events.c \
82 | ../libavr32/src/libfixmath/fix16.c \
83 | ../libavr32/src/i2c.c \
84 | ../libavr32/src/init_ansible.c \
85 | ../libavr32/src/init_common.c \
86 | ../libavr32/src/interrupts.c \
87 | ../libavr32/src/midi_common.c \
88 | ../libavr32/src/monome.c \
89 | ../libavr32/src/music.c \
90 | ../libavr32/src/notes.c \
91 | ../libavr32/src/random.c \
92 | ../libavr32/src/timers.c \
93 | ../libavr32/src/usb.c \
94 | ../libavr32/src/util.c \
95 | ../libavr32/src/json/encoding.c \
96 | ../libavr32/src/json/serdes.c \
97 | ../libavr32/src/json/jsmn/jsmn.c \
98 | ../libavr32/src/usb/ftdi/ftdi.c \
99 | ../libavr32/src/usb/ftdi/uhi_ftdi.c \
100 | ../libavr32/src/usb/hid/hid.c \
101 | ../libavr32/src/usb/hid/uhi_hid.c \
102 | ../libavr32/src/usb/midi/uhi_midi.c \
103 | ../libavr32/src/usb/midi/midi.c \
104 | ../libavr32/src/usb/msc/msc.c \
105 | ../libavr32/src/usb/cdc/cdc.c \
106 | ../libavr32/src/usb/cdc/uhi_cdc.c \
107 | ../libavr32/asf/common/services/storage/ctrl_access/ctrl_access.c \
108 | avr32/drivers/adc/adc.c \
109 | avr32/drivers/flashc/flashc.c \
110 | avr32/drivers/gpio/gpio.c \
111 | avr32/drivers/intc/intc.c \
112 | avr32/drivers/pm/pm.c \
113 | avr32/drivers/pm/pm_conf_clocks.c \
114 | avr32/drivers/pm/power_clocks_lib.c \
115 | avr32/drivers/spi/spi.c \
116 | avr32/drivers/tc/tc.c \
117 | avr32/drivers/twi/twi.c \
118 | avr32/drivers/usart/usart.c \
119 | avr32/drivers/usbb/usbb_host.c \
120 | avr32/services/fs/fat/fat.c \
121 | avr32/services/fs/fat/fat_unusual.c \
122 | avr32/services/fs/fat/file.c \
123 | avr32/services/fs/fat/navigation.c \
124 | avr32/utils/debug/print_funcs.c \
125 | common/services/usb/class/msc/host/uhi_msc.c \
126 | common/services/usb/class/msc/host/uhi_msc_mem.c \
127 | common/services/spi/uc3_spi/spi_master.c \
128 | common/services/usb/uhc/uhc.c \
129 | common/services/clock/uc3b0_b1/sysclk.c
130 |
131 | # List of assembler source files.
132 | ASSRCS = \
133 | avr32/utils/startup/trampoline_uc3.S \
134 | avr32/drivers/intc/exception.S \
135 |
136 |
137 | # List of include paths.
138 | INC_PATH = \
139 | ../../src \
140 | ../src \
141 | ../src/usb \
142 | ../src/usb/cdc \
143 | ../src/usb/ftdi \
144 | ../src/usb/hid \
145 | ../src/usb/midi \
146 | ../src/usb/msc \
147 | ../conf \
148 | ../conf/trilogy \
149 | ../libavr32/src \
150 | avr32/boards \
151 | avr32/drivers/cpu/cycle_counter \
152 | avr32/drivers/flashc \
153 | avr32/drivers/gpio \
154 | avr32/drivers/intc \
155 | avr32/drivers/pm \
156 | avr32/drivers/spi \
157 | avr32/drivers/tc \
158 | avr32/drivers/twi \
159 | avr32/drivers/usart \
160 | avr32/drivers/usbb \
161 | avr32/services/fs/fat \
162 | avr32/utils \
163 | avr32/utils/debug \
164 | avr32/utils/preprocessor \
165 | common/boards \
166 | common/boards/user_board \
167 | common/services/storage/ctrl_access \
168 | common/services/clock \
169 | common/services/delay \
170 | common/services/usb/ \
171 | common/services/usb/uhc \
172 | common/services/usb/class/msc \
173 | common/services/usb/class/msc/host \
174 | common/services/usb/class/hid \
175 | common/services/spi/uc3_spi \
176 | common/utils
177 |
178 | # Additional search paths for libraries.
179 | LIB_PATH =
180 |
181 | # List of libraries to use during linking.
182 | LIBS =
183 |
184 | # Path relative to top level directory pointing to a linker script.
185 | # LINKER_SCRIPT = avr32/utils/linker_scripts/at32uc3b/0256/gcc/link_uc3b0256.lds
186 | # LINKER_SCRIPT = avr32/drivers/flashc/flash_example/at32uc3b0256_evk1101/link_uc3b0256.lds
187 | LINKER_SCRIPT = ../../libavr32/src/link_uc3b0512.lds
188 |
189 |
190 | # Additional options for debugging. By default the common Makefile.in will
191 | # add -g3.
192 | DBGFLAGS =
193 |
194 | # Application optimization used during compilation and linking:
195 | # -O0, -O1, -O2, -O3 or -Os
196 | OPTIMIZATION = -Os
197 |
198 | # Extra flags to use when archiving.
199 | ARFLAGS =
200 |
201 | # Extra flags to use when assembling.
202 | ASFLAGS =
203 |
204 | # Extra flags to use when compiling.
205 | CFLAGS =
206 |
207 | # Extra flags to use when preprocessing.
208 | #
209 | # Preprocessor symbol definitions
210 | # To add a definition use the format "-D name[=definition]".
211 | # To cancel a definition use the format "-U name".
212 | #
213 | # The most relevant symbols to define for the preprocessor are:
214 | # BOARD Target board in use, see boards/board.h for a list.
215 | # EXT_BOARD Optional extension board in use, see boards/board.h for a list.
216 | CPPFLAGS = \
217 | -D BOARD=USER_BOARD -D UHD_ENABLE
218 |
219 | # Extra flags to use when linking
220 | LDFLAGS = \
221 | -Wl,-e,_trampoline
222 |
223 | # Pre- and post-build commands
224 | PREBUILD_CMD =
225 | POSTBUILD_CMD =
226 |
227 | ansible: all
228 |
229 | ../src/gitversion.c: ../.git/HEAD ../.git/index
230 | echo 'const char git_version[] = "$(shell git describe --tags | cut -f1 -d'-')-$(shell git describe --always --dirty)";' > $@
231 |
--------------------------------------------------------------------------------
/src/flash.sh:
--------------------------------------------------------------------------------
1 | dfu-programmer at32uc3b0512 erase
2 | dfu-programmer at32uc3b0512 flash ansible.hex --suppress-bootloader-mem
3 | dfu-programmer at32uc3b0512 start
4 |
--------------------------------------------------------------------------------
/src/gitversion.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | extern const char git_version[];
4 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | b00 led1
4 | b01 led2
5 |
6 | b02 tr1
7 | b03 tr2
8 | b04 tr3
9 | b05 tr4
10 |
11 | b06 k1
12 | b07 k2
13 |
14 | b08 in1
15 | b09 in2
16 | b10 in1-detect
17 |
18 | nmi
19 |
20 |
21 | usb flash
22 |
23 | */
24 |
25 |
26 | #include
27 | #include // memcpy
28 |
29 | // asf
30 | #include "delay.h"
31 | #include "compiler.h"
32 | #include "flashc.h"
33 | #include "preprocessor.h"
34 | #include "print_funcs.h"
35 | #include "intc.h"
36 | #include "pm.h"
37 | #include "gpio.h"
38 | #include "spi.h"
39 | #include "sysclk.h"
40 |
41 | // libavr32
42 | #include "types.h"
43 | #include "events.h"
44 | #include "libfixmath/fix16.h"
45 | #include "i2c.h"
46 | #include "init_ansible.h"
47 | #include "init_common.h"
48 | #include "monome.h"
49 | #include "midi.h"
50 | #include "music.h"
51 | #include "notes.h"
52 | #include "timers.h"
53 | #include "util.h"
54 | #include "ftdi.h"
55 | #include "ii.h"
56 | #include "dac.h"
57 | #include "cdc.h"
58 |
59 |
60 | #include "conf_board.h"
61 |
62 | // ansible
63 | #include "main.h"
64 | #include "ansible_grid.h"
65 | #include "ansible_arc.h"
66 | #include "ansible_midi.h"
67 | #include "ansible_tt.h"
68 | #include "ansible_usb_disk.h"
69 | #include "ansible_ii_leader.h"
70 |
71 |
72 | #define FIRSTRUN_KEY 0x22
73 |
74 | uint8_t front_timer;
75 |
76 | uint8_t preset_mode;
77 |
78 | __attribute__((__section__(".flash_nvram")))
79 | nvram_data_t f;
80 |
81 | ansible_mode_t ansible_mode;
82 |
83 | bool leader_mode = false;
84 | uint16_t aux_param[2][4] = { { 0 } };
85 |
86 | ////////////////////////////////////////////////////////////////////////////////
87 | // prototypes
88 |
89 | // start/stop monome polling/refresh timers
90 | extern void timers_set_monome(void);
91 | extern void timers_unset_monome(void);
92 |
93 | // check the event queue
94 | static void check_events(void);
95 |
96 | // handler protos
97 | static void handler_KeyTimer(s32 data);
98 | static void handler_Front(s32 data);
99 | static void handler_FrontShort(s32 data);
100 | static void handler_FrontLong(s32 data);
101 | static void handler_MidiConnect(s32 data);
102 | static void handler_MidiDisconnect(s32 data);
103 |
104 | u8 flash_is_fresh(void);
105 | void flash_write(void);
106 | void flash_read(void);
107 | void state_write(void);
108 | void state_read(void);
109 |
110 | void ii_ansible(uint8_t* d, uint8_t len);
111 | static ansible_mode_t ii_ansible_mode_for_cmd(uint8_t cmd);
112 | static uint8_t ii_ansible_cmd_for_mode(ansible_mode_t mode);
113 | ////////////////////////////////////////////////////////////////////////////////
114 | // timers
115 |
116 | static softTimer_t clockTimer = { .next = NULL, .prev = NULL };
117 | static softTimer_t keyTimer = { .next = NULL, .prev = NULL };
118 | static softTimer_t cvTimer = { .next = NULL, .prev = NULL };
119 | static softTimer_t monomePollTimer = { .next = NULL, .prev = NULL };
120 | static softTimer_t monomeRefreshTimer = { .next = NULL, .prev = NULL };
121 | static softTimer_t midiPollTimer = { .next = NULL, .prev = NULL };
122 |
123 | softTimer_t auxTimer[4] = {
124 | { .next = NULL, .prev = NULL },
125 | { .next = NULL, .prev = NULL },
126 | { .next = NULL, .prev = NULL },
127 | { .next = NULL, .prev = NULL }
128 | };
129 |
130 | uint16_t tuning_table[4][120];
131 |
132 | ansible_output_t outputs[4];
133 |
134 | static uint8_t clock_phase;
135 |
136 | void handler_None(s32 data) { ;; }
137 |
138 | static void clockTimer_callback(void* o) {
139 | clock_phase++;
140 | if(clock_phase > 1)
141 | clock_phase = 0;
142 | clock(clock_phase);
143 | }
144 |
145 | static void keyTimer_callback(void* o) {
146 | static event_t e;
147 | e.type = kEventKeyTimer;
148 | e.data = 0;
149 | event_post(&e);
150 | }
151 |
152 | static void cvTimer_callback(void* o) {
153 | dac_timer_update();
154 | }
155 |
156 | static void monome_poll_timer_callback(void* obj) {
157 | serial_read();
158 | }
159 |
160 | static void monome_refresh_timer_callback(void* obj) {
161 | if(monomeFrameDirty > 0) {
162 | static event_t e;
163 | e.type = kEventMonomeRefresh;
164 | event_post(&e);
165 | }
166 | }
167 |
168 | static void midi_poll_timer_callback(void* obj) {
169 | midi_read();
170 | }
171 |
172 | void timers_set_monome(void) {
173 | timer_add(&monomePollTimer, 20, &monome_poll_timer_callback, NULL );
174 | timer_add(&monomeRefreshTimer, 30, &monome_refresh_timer_callback, NULL );
175 | }
176 |
177 | void timers_unset_monome(void) {
178 | timer_remove( &monomePollTimer );
179 | timer_remove( &monomeRefreshTimer );
180 | }
181 |
182 | void set_mode(ansible_mode_t m) {
183 | ansible_mode = m;
184 | // flashc_memset32((void*)&(f.state.mode), m, 4, true);
185 | // print_dbg("\r\nset mode ");
186 | // print_dbg_ulong(f.state.mode);
187 |
188 | timer_remove(&auxTimer[0]);
189 | timer_remove(&auxTimer[1]);
190 | timer_remove(&auxTimer[2]);
191 | timer_remove(&auxTimer[3]);
192 |
193 | switch (m) {
194 | case mGridKria:
195 | case mGridMP:
196 | case mGridES:
197 | set_mode_grid();
198 | break;
199 | case mArcLevels:
200 | case mArcCycles:
201 | set_mode_arc();
202 | break;
203 | case mMidiStandard:
204 | case mMidiArp:
205 | set_mode_midi();
206 | break;
207 | case mTT:
208 | set_mode_tt();
209 | break;
210 | case mUsbDisk:
211 | set_mode_usb_disk();
212 | break;
213 | default:
214 | break;
215 | }
216 | }
217 |
218 | ////////////////////////////////////////////////////////////////////////////////
219 | // event handlers
220 |
221 | static void handler_FtdiConnect(s32 data) {
222 | ftdi_setup();
223 | }
224 |
225 | static void handler_SerialConnect(s32 data) {
226 | monome_setup_mext();
227 | }
228 |
229 | static void handler_FtdiDisconnect(s32 data) {
230 | timers_unset_monome();
231 | app_event_handlers[ kEventFrontShort ] = &handler_FrontShort;
232 | app_event_handlers[ kEventFrontLong ] = &handler_FrontLong;
233 | connected = conNONE;
234 | // set_mode(f.state.mode);
235 | }
236 |
237 | static void handler_MonomeConnect(s32 data) {
238 | print_dbg("\r\n> connect: monome ");
239 |
240 | switch (monome_device()) {
241 | case eDeviceGrid:
242 | print_dbg("GRID");
243 | connected = conGRID;
244 | if(ansible_mode != f.state.grid_mode)
245 | set_mode(f.state.grid_mode);
246 | monomeFrameDirty++;
247 | app_event_handlers[kEventFrontShort] = &handler_GridFrontShort;
248 | app_event_handlers[kEventFrontLong] = &handler_GridFrontLong;
249 | break;
250 | case eDeviceArc:
251 | print_dbg("ARC");
252 | connected = conARC;
253 | if(ansible_mode != f.state.arc_mode)
254 | set_mode(f.state.arc_mode);
255 | monomeFrameDirty++;
256 | app_event_handlers[kEventFrontShort] = &handler_ArcFrontShort;
257 | app_event_handlers[kEventFrontLong] = &handler_ArcFrontLong;
258 | break;
259 | default:
260 | break;
261 | }
262 | timers_set_monome();
263 | }
264 |
265 | static void handler_MonomePoll(s32 data) {
266 | monome_read_serial();
267 | }
268 |
269 | static void handler_MidiConnect(s32 data) {
270 | print_dbg("\r\n> midi connect");
271 | timer_add(&midiPollTimer, 8, &midi_poll_timer_callback, NULL);
272 | connected = conMIDI;
273 | flashc_memset32((void*)&(f.state.none_mode), mTT, 4, true);
274 | set_mode(f.state.midi_mode);
275 | }
276 |
277 | static void handler_MidiDisconnect(s32 data) {
278 | print_dbg("\r\n> midi disconnect");
279 | timer_remove(&midiPollTimer);
280 | app_event_handlers[ kEventFrontShort ] = &handler_FrontShort;
281 | app_event_handlers[ kEventFrontLong ] = &handler_FrontLong;
282 | connected = conNONE;
283 | set_mode(mTT);
284 | }
285 |
286 | static volatile bool front_held = false;
287 |
288 | static void handler_MscConnect(s32 data) {
289 | print_dbg("\r\n> usb disk connect");
290 | if (front_held) {
291 | usb_disk_select_app(ansible_mode);
292 | }
293 | set_mode(mUsbDisk);
294 | }
295 |
296 | static void handler_MscDisconnect(s32 data) {
297 | print_dbg("\r\n> usb disk disconnect");
298 | usb_disk_exit();
299 | update_leds(0);
300 | app_event_handlers[kEventFront] = &handler_Front;
301 | usb_disk_skip_apps(false);
302 | }
303 |
304 | static void handler_Front(s32 data) {
305 | // print_dbg("\r\n+ front ");
306 | // print_dbg_ulong(data);
307 |
308 | if(data == 1) {
309 | front_timer = KEY_HOLD_TIME;
310 | front_held = true;
311 | }
312 | else {
313 | front_held = false;
314 | if(front_timer) {
315 | static event_t e;
316 | e.type = kEventFrontShort;
317 | e.data = 0;
318 | event_post(&e);
319 | }
320 | front_timer = 0;
321 | }
322 | }
323 |
324 | static void handler_FrontShort(s32 data) {
325 | if(ansible_mode != mTT) {
326 | flashc_memset32((void*)&(f.state.none_mode), mTT, 4, true);
327 | set_mode(mTT);
328 | }
329 | }
330 |
331 | static void handler_FrontLong(s32 data) {
332 | print_dbg("\r\n+ front long");
333 | uint8_t addr = 0xA0 + (!gpio_get_pin_value(B07) * 2) + (!gpio_get_pin_value(B06) * 4);
334 | flashc_memset8((void*)&(f.state.i2c_addr), addr, 1, true);
335 | print_dbg("\r\n+ i2c address: ");
336 | print_dbg_hex(f.state.i2c_addr);
337 | // TEST
338 | if (!leader_mode) init_i2c_follower(f.state.i2c_addr);
339 | }
340 |
341 | static void handler_SaveFlash(s32 data) {
342 | flash_write();
343 | }
344 |
345 | static void handler_KeyTimer(s32 data) {
346 | static uint8_t key0_state;
347 | static uint8_t key1_state;
348 | static uint8_t keyfront_state;
349 | static uint8_t tr0normal_state;
350 |
351 | if(key0_state != !gpio_get_pin_value(B07)) {
352 | key0_state = !gpio_get_pin_value(B07);
353 | static event_t e;
354 | e.type = kEventKey;
355 | e.data = key0_state;
356 | event_post(&e);
357 | }
358 |
359 | if(key1_state != !gpio_get_pin_value(B06)) {
360 | key1_state = !gpio_get_pin_value(B06);
361 | static event_t e;
362 | e.type = kEventKey;
363 | e.data = key1_state + 2;
364 | event_post(&e);
365 | }
366 |
367 | if(keyfront_state != !gpio_get_pin_value(NMI)) {
368 | keyfront_state = !gpio_get_pin_value(NMI);
369 | static event_t e;
370 | e.type = kEventFront;
371 | e.data = keyfront_state;
372 | event_post(&e);
373 | }
374 |
375 | if(tr0normal_state != !gpio_get_pin_value(B10)) {
376 | tr0normal_state = !gpio_get_pin_value(B10);
377 | static event_t e;
378 | e.type = kEventTrNormal;
379 | e.data = tr0normal_state;
380 | event_post(&e);
381 | }
382 |
383 | if(front_timer) {
384 | if(front_timer == 1) {
385 | static event_t e;
386 | e.type = kEventFrontLong;
387 | e.data = 0;
388 | event_post(&e);
389 | }
390 | front_timer--;
391 | }
392 |
393 | if(connected == conGRID)
394 | grid_keytimer();
395 | else if(connected == conARC)
396 | arc_keytimer();
397 | }
398 |
399 | // assign default event handlers
400 | static inline void assign_main_event_handlers(void) {
401 | app_event_handlers[ kEventFront ] = &handler_Front;
402 | app_event_handlers[ kEventFrontShort ] = &handler_FrontShort;
403 | app_event_handlers[ kEventFrontLong ] = &handler_FrontLong;
404 | app_event_handlers[ kEventKeyTimer ] = &handler_KeyTimer;
405 | app_event_handlers[ kEventSaveFlash ] = &handler_SaveFlash;
406 | app_event_handlers[ kEventFtdiConnect ] = &handler_FtdiConnect ;
407 | app_event_handlers[ kEventFtdiDisconnect ] = &handler_FtdiDisconnect ;
408 | app_event_handlers[ kEventMscConnect ] = &handler_MscConnect ;
409 | app_event_handlers[ kEventMscDisconnect ] = &handler_MscDisconnect ;
410 | app_event_handlers[ kEventMonomeConnect ] = &handler_MonomeConnect ;
411 | app_event_handlers[ kEventMonomeDisconnect ] = &handler_None ;
412 | app_event_handlers[ kEventMonomePoll ] = &handler_MonomePoll ;
413 | app_event_handlers[ kEventMonomeRefresh ] = &handler_None ;
414 | app_event_handlers[ kEventMonomeGridKey ] = &handler_None ;
415 | app_event_handlers[ kEventMonomeRingEnc ] = &handler_None ;
416 | app_event_handlers[ kEventTr ] = &handler_None ;
417 | app_event_handlers[ kEventTrNormal ] = &handler_None ;
418 | app_event_handlers[ kEventKey ] = &handler_None ;
419 | app_event_handlers[ kEventMidiConnect ] = &handler_MidiConnect ;
420 | app_event_handlers[ kEventMidiDisconnect ] = &handler_MidiDisconnect ;
421 | app_event_handlers[ kEventMidiPacket ] = &handler_None;
422 | app_event_handlers[ kEventSerialConnect ] = &handler_SerialConnect ;
423 | app_event_handlers[ kEventSerialDisconnect ] = &handler_FtdiDisconnect ;
424 | }
425 |
426 | // app event loop
427 | void check_events(void) {
428 | static event_t e;
429 | if( event_next(&e) ) {
430 | (app_event_handlers)[e.type](e.data);
431 | }
432 | }
433 |
434 |
435 |
436 | ////////////////////////////////////////////////////////////////////////////////
437 | // flash
438 |
439 | u8 flash_is_fresh(void) {
440 | return (f.fresh != FIRSTRUN_KEY);
441 | }
442 |
443 | void flash_unfresh(void) {
444 | flashc_memset8((void*)&(f.fresh), FIRSTRUN_KEY, 1, true);
445 | }
446 |
447 | void flash_write(void) {
448 | print_dbg("\r\n> write preset ");
449 | // print_dbg_ulong(preset_select);
450 | // flashc_memset8((void*)&(f.preset_select), preset_select, 4, true);
451 |
452 | // flashc_memcpy((void *)&(f.state), &ansible_state, sizeof(ansible_state), true);
453 | }
454 |
455 | void flash_read(void) {
456 | print_dbg("\r\n> read preset ");
457 | // print_dbg_ulong(preset_select);
458 |
459 | // preset_select = f.preset_select;
460 |
461 | // memcpy(&ansible_state, &f.state, sizeof(ansible_state));
462 |
463 | // ...
464 | }
465 |
466 | ////////////////////////////////////////////////////////////////////////////////
467 | // tuning
468 |
469 | void default_tuning(void) {
470 | for (uint8_t i = 0; i < 4; i++) {
471 | for (uint8_t j = 0; j < 120; j++) {
472 | tuning_table[i][j] = ET[j];
473 | }
474 | }
475 | flashc_memcpy((void *)f.tuning_table, tuning_table, sizeof(tuning_table), true);
476 | }
477 |
478 | void init_tuning(void) {
479 | memcpy((void *)&tuning_table, &f.tuning_table, sizeof(tuning_table));
480 | }
481 |
482 | void fit_tuning(int mode) {
483 | switch (mode) {
484 | case 0: { // fixed offset per channel
485 | for (uint8_t i = 0; i < 4; i++) {
486 | uint16_t offset = tuning_table[i][0];
487 | for (uint8_t j = 0; j < 120; j++) {
488 | tuning_table[i][j] = ET[j] + offset;
489 | }
490 | }
491 | break;
492 | }
493 | case 1: { // linear fit between octaves
494 | for (uint8_t i = 0; i < 4; i++) {
495 | fix16_t step = 0;
496 | for (uint8_t j = 0; j < 10; j++) {
497 | fix16_t acc = fix16_from_int(tuning_table[i][j*12]);
498 | if (j < 9) {
499 | step = fix16_div(
500 | fix16_from_int(tuning_table[i][(j+1)*12] - tuning_table[i][j*12]),
501 | fix16_from_int(12));
502 | }
503 | for (uint8_t k = j*12; k < (j+1)*12; k++) {
504 | tuning_table[i][k] = fix16_to_int(acc);
505 | acc = fix16_add(acc, step);
506 | }
507 | }
508 | }
509 | break;
510 | }
511 | default: break;
512 | }
513 | }
514 |
515 | ////////////////////////////////////////////////////////////////////////////////
516 | // functions
517 |
518 | void clock_null(u8 phase) { ;; }
519 |
520 | void update_leds(uint8_t m) {
521 | if(m & 1)
522 | gpio_set_gpio_pin(B00);
523 | else
524 | gpio_clr_gpio_pin(B00);
525 |
526 |
527 | if(m & 2)
528 | gpio_set_gpio_pin(B01);
529 | else
530 | gpio_clr_gpio_pin(B01);
531 | }
532 |
533 | void set_tr(uint8_t n) {
534 | gpio_set_gpio_pin(n);
535 | uint8_t tr = n - TR1;
536 | outputs[tr].tr = true;
537 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
538 | bool play_follower = followers[i].active
539 | && followers[i].track_en & (1 << tr);
540 | if (play_follower) {
541 | followers[i].ops->tr(&followers[i], tr, 1);
542 | }
543 | }
544 | }
545 |
546 | void clr_tr(uint8_t n) {
547 | gpio_clr_gpio_pin(n);
548 | uint8_t tr = n - TR1;
549 | outputs[tr].tr = false;
550 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
551 | bool play_follower = followers[i].active
552 | && followers[i].track_en & (1 << tr);
553 | if (play_follower) {
554 | followers[i].ops->tr(&followers[i], tr, 0);
555 | }
556 | }
557 | }
558 |
559 | uint8_t get_tr(uint8_t n) {
560 | return gpio_get_pin_value(n);
561 | }
562 |
563 | void set_cv_note_noii(uint8_t n, uint16_t note, int16_t bend) {
564 | outputs[n].semitones = note;
565 | outputs[n].bend = bend;
566 | outputs[n].dac_target = (int16_t)tuning_table[n][note] + bend;
567 | dac_set_value(n, outputs[n].dac_target);
568 | }
569 |
570 | void set_cv_note(uint8_t n, uint16_t note, int16_t bend) {
571 | set_cv_note_noii(n, note, bend);
572 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
573 | bool play_follower = followers[i].active
574 | && followers[i].track_en & (1 << n);
575 | if (play_follower) {
576 | uint16_t cv_transposed = (int16_t)ET[note] + bend;
577 | followers[i].ops->cv(&followers[i], n, cv_transposed);
578 | }
579 | }
580 | }
581 |
582 | void set_cv_slew(uint8_t n, uint16_t s) {
583 | outputs[n].slew = s;
584 | dac_set_slew(n, outputs[n].slew);
585 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
586 | bool play_follower = followers[i].active
587 | && followers[i].track_en & (1 << n);
588 | if (play_follower) {
589 | followers[i].ops->slew(&followers[i], n, s);
590 | }
591 | }
592 | }
593 |
594 | void reset_outputs(void) {
595 | for (uint8_t n = 0; n < 4; n++) {
596 | outputs[n].slew = 0;
597 | dac_set_slew(n, 0);
598 | outputs[n].tr = false;
599 | gpio_clr_gpio_pin(n + TR1);
600 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
601 | bool play_follower = followers[i].active
602 | && followers[i].track_en & (1 << n);
603 | if (play_follower) {
604 | followers[i].ops->mute(&followers[n], 0, 0);
605 | }
606 | }
607 | }
608 | }
609 |
610 | static void follower_on(uint8_t n) {
611 | for (uint8_t i = 0; i < 4; i++) {
612 | followers[n].ops->init(&followers[n], i, 1);
613 | followers[n].ops->mode(&followers[n], i, followers[n].active_mode);
614 | followers[n].ops->octave(&followers[n], 0, followers[n].oct);
615 | }
616 | }
617 |
618 | static void follower_off(uint8_t n) {
619 | for (uint8_t i = 0; i < 4; i++) {
620 | followers[n].ops->init(&followers[n], i, 0);
621 | }
622 | }
623 |
624 | void toggle_follower(uint8_t n) {
625 | followers[n].active = !followers[n].active;
626 | if (followers[n].active) {
627 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
628 | if (i != n && followers[i].active) {
629 | follower_on(n);
630 | return;
631 | }
632 | }
633 | print_dbg("\r\n> enter i2c leader mode");
634 | leader_mode = true;
635 | init_i2c_leader();
636 | follower_on(n);
637 | }
638 | else {
639 | follower_off(n);
640 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
641 | if (i != n && followers[i].active) {
642 | return;
643 | }
644 | }
645 | print_dbg("\r\n> exit i2c leader mode");
646 | leader_mode = false;
647 | ii_follower_resume();
648 | }
649 | }
650 |
651 | void ii_follower_pause(void) {
652 | if (!leader_mode) {
653 | // 0x03 is a reserved address 'for future use' in the i2c spec
654 | // used to effectively stop listening for i2c
655 | init_i2c_follower(0x03);
656 | }
657 | }
658 |
659 | void ii_follower_resume(void) {
660 | if (!leader_mode) {
661 | switch (ansible_mode) {
662 | case mArcLevels:
663 | init_i2c_follower(II_LV_ADDR);
664 | break;
665 | case mArcCycles:
666 | init_i2c_follower(II_CY_ADDR);
667 | break;
668 | case mGridKria:
669 | init_i2c_follower(II_KR_ADDR);
670 | break;
671 | case mGridMP:
672 | init_i2c_follower(II_MP_ADDR);
673 | break;
674 | case mGridES:
675 | init_i2c_follower(ES);
676 | break;
677 | case mMidiStandard:
678 | init_i2c_follower(II_MID_ADDR);
679 | break;
680 | case mMidiArp:
681 | init_i2c_follower(II_ARP_ADDR);
682 | break;
683 | case mTT:
684 | init_i2c_follower(f.state.i2c_addr);
685 | break;
686 | default:
687 | break;
688 | }
689 | }
690 | }
691 |
692 | void clock_set(uint32_t n) {
693 | timer_set(&clockTimer, n);
694 | }
695 |
696 | void clock_set_tr(uint32_t n, uint8_t phase) {
697 | timer_set(&clockTimer, n);
698 | clock_phase = phase;
699 | timer_manual(&clockTimer);
700 | }
701 |
702 | ///////
703 | // global ii handlers
704 | void load_flash_state(void) {
705 | init_tuning();
706 | init_levels();
707 | init_cycles();
708 | init_kria();
709 | init_mp();
710 | init_es();
711 | init_tt();
712 |
713 | print_dbg("\r\ni2c addr: ");
714 | print_dbg_hex(f.state.i2c_addr);
715 |
716 | leader_mode = false;
717 | memcpy((void*)followers, f.state.followers, sizeof(followers));
718 | for (uint8_t i = 0; i < I2C_FOLLOWER_COUNT; i++) {
719 | if (followers[i].active) {
720 | if (!leader_mode) {
721 | leader_mode = true;
722 | // wait to allow for any i2c devices to fully initalise
723 | delay_ms(1500);
724 | init_i2c_leader();
725 | }
726 | follower_on(i);
727 | }
728 | }
729 | if (!leader_mode) {
730 | init_i2c_follower(f.state.i2c_addr);
731 | }
732 | }
733 |
734 | void ii_ansible(uint8_t* d, uint8_t len) {
735 | // print_dbg("\r\nii/ansible (");
736 | // print_dbg_ulong(len);
737 | // print_dbg(") ");
738 | // for(int i=0;i= 2 ) {
750 | ansible_mode_t next_mode = ii_ansible_mode_for_cmd(d[1]);
751 | if (next_mode < 0) {
752 | break;
753 | }
754 | set_mode(next_mode);
755 | }
756 | break;
757 | case II_ANSIBLE_APP + II_GET: {
758 | uint8_t cmd = ii_ansible_cmd_for_mode(ansible_mode);
759 | ii_tx_queue(cmd);
760 | break;
761 | }
762 | default:
763 | break;
764 | }
765 | }
766 |
767 | static ansible_mode_t ii_ansible_mode_for_cmd(uint8_t cmd) {
768 | switch (cmd) {
769 | case 0: return mArcLevels;
770 | case 1: return mArcCycles;
771 | case 2: return mGridKria;
772 | case 3: return mGridMP;
773 | case 4: return mGridES;
774 | case 5: return mMidiStandard;
775 | case 6: return mMidiArp;
776 | case 7: return mTT;
777 | default: return -1;
778 | }
779 | }
780 |
781 | static uint8_t ii_ansible_cmd_for_mode(ansible_mode_t mode) {
782 | switch (mode) {
783 | case mArcLevels: return 0;
784 | case mArcCycles: return 1;
785 | case mGridKria: return 2;
786 | case mGridMP: return 3;
787 | case mGridES: return 4;
788 | case mMidiStandard: return 5;
789 | case mMidiArp: return 6;
790 | case mTT: return 7;
791 | default: return -1;
792 | }
793 | }
794 |
795 |
796 | ////////////////////////////////////////////////////////////////////////////////
797 | ////////////////////////////////////////////////////////////////////////////////
798 | ////////////////////////////////////////////////////////////////////////////////
799 | // main
800 |
801 | int main(void)
802 | {
803 | sysclk_init();
804 |
805 | init_dbg_rs232(FMCK_HZ);
806 |
807 | print_dbg("\r\n\n// ansible //////////////////////////////// ");
808 | print_dbg("\r\n== FLASH struct size: ");
809 | print_dbg_ulong(sizeof(f));
810 |
811 |
812 | if(flash_is_fresh()) {
813 | // store flash defaults
814 | print_dbg("\r\nfirst run.");
815 | flashc_memset32((void*)&(f.state.none_mode), mTT, 4, true);
816 | flashc_memset32((void*)&(f.state.grid_mode), mGridKria, 4, true);
817 | flashc_memset32((void*)&(f.state.arc_mode), mArcLevels, 4, true);
818 | flashc_memset32((void*)&(f.state.midi_mode), mMidiStandard, 4, true);
819 | flashc_memset8((void*)&(f.state.i2c_addr), 0xA0, 1, true);
820 | flashc_memset8((void*)&(f.state.grid_varibrightness), 16, 1, true);
821 | flashc_memcpy((void*)f.state.followers, followers, sizeof(followers), true);
822 | default_tuning();
823 | default_kria();
824 | default_mp();
825 | default_es();
826 | default_levels();
827 | default_cycles();
828 | default_midi_standard();
829 | default_midi_arp();
830 | default_tt();
831 |
832 | flash_unfresh();
833 | }
834 |
835 | init_gpio();
836 | assign_main_event_handlers();
837 | init_events();
838 | init_tc();
839 | init_spi();
840 | // init_adc();
841 |
842 | irq_initialize_vectors();
843 | register_interrupts();
844 | cpu_irq_enable();
845 |
846 | load_flash_state();
847 | process_ii = &ii_ansible;
848 |
849 | clr_tr(TR1);
850 | clr_tr(TR2);
851 | clr_tr(TR3);
852 | clr_tr(TR4);
853 |
854 | clock = &clock_null;
855 |
856 | timer_add(&clockTimer,1000,&clockTimer_callback, NULL);
857 | timer_add(&keyTimer,50,&keyTimer_callback, NULL);
858 | timer_add(&cvTimer,DAC_RATE_CV,&cvTimer_callback, NULL);
859 |
860 | init_dacs();
861 |
862 | connected = conNONE;
863 | set_mode(f.state.none_mode);
864 |
865 | init_usb_host();
866 | init_monome();
867 |
868 | while (true) {
869 | check_events();
870 | }
871 | }
872 |
--------------------------------------------------------------------------------
/src/main.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "timers.h"
4 |
5 | #include "ansible_grid.h"
6 | #include "ansible_arc.h"
7 | #include "ansible_midi.h"
8 | #include "ansible_tt.h"
9 | #include "ansible_ii_leader.h"
10 |
11 | #define TR1 B02
12 | #define TR2 B03
13 | #define TR3 B04
14 | #define TR4 B05
15 |
16 | #define KEY_HOLD_TIME 8
17 |
18 | // WARNING: order must match array order of
19 | // connected_t_options[], ansible_mode_options[]
20 | // in ansible_preset_docdef.c
21 | typedef enum {
22 | conNONE,
23 | conARC,
24 | conGRID,
25 | conMIDI,
26 | conFLASH
27 | } connected_t;
28 |
29 | typedef enum {
30 | mArcLevels,
31 | mArcCycles,
32 | mGridKria,
33 | mGridMP,
34 | mGridES,
35 | mMidiStandard,
36 | mMidiArp,
37 | mTT,
38 | mUsbDisk,
39 | } ansible_mode_t;
40 | // END WARNING
41 |
42 | connected_t connected;
43 |
44 |
45 |
46 | extern bool leader_mode;
47 | extern uint16_t aux_param[2][4];
48 |
49 | typedef struct {
50 | connected_t connected;
51 | ansible_mode_t arc_mode;
52 | ansible_mode_t grid_mode;
53 | ansible_mode_t midi_mode;
54 | ansible_mode_t none_mode;
55 | uint8_t i2c_addr;
56 | uint8_t grid_varibrightness;
57 | i2c_follower_t followers[I2C_FOLLOWER_COUNT];
58 | } ansible_state_t;
59 |
60 |
61 | // NVRAM data structure located in the flash array.
62 | typedef const struct {
63 | uint8_t fresh;
64 | ansible_state_t state;
65 | kria_state_t kria_state;
66 | mp_state_t mp_state;
67 | es_state_t es_state;
68 | levels_state_t levels_state;
69 | cycles_state_t cycles_state;
70 | midi_standard_state_t midi_standard_state;
71 | midi_arp_state_t midi_arp_state;
72 | tt_state_t tt_state;
73 | uint8_t scale[16][8];
74 | uint16_t tuning_table[4][120];
75 | } nvram_data_t;
76 |
77 | typedef struct {
78 | bool tr;
79 | uint16_t semitones;
80 | int16_t bend;
81 | uint16_t slew;
82 | uint16_t dac_target;
83 | } ansible_output_t;
84 |
85 | extern nvram_data_t f;
86 | extern ansible_mode_t ansible_mode;
87 | extern i2c_follower_t followers[I2C_FOLLOWER_COUNT];
88 |
89 | extern softTimer_t auxTimer[4];
90 | extern uint16_t tuning_table[4][120];
91 | extern ansible_output_t outputs[4];
92 |
93 | void (*clock)(u8 phase);
94 | void init_tuning(void);
95 | void default_tuning(void);
96 | void fit_tuning(int mode);
97 |
98 | extern void handler_None(s32 data);
99 | extern void clock_null(u8 phase);
100 | extern void ii_null(uint8_t *d, uint8_t l);
101 | extern void ii_follower_pause(void);
102 | extern void ii_follower_resume(void);
103 |
104 | void set_mode(ansible_mode_t m);
105 | void update_leds(uint8_t m);
106 | void set_tr(uint8_t n);
107 | void clr_tr(uint8_t n);
108 | void set_cv_note_noii(uint8_t n, uint16_t cv, int16_t bend);
109 | void set_cv_note(uint8_t n, uint16_t cv, int16_t bend);
110 | void set_cv_slew(uint8_t n, uint16_t s);
111 | void reset_outputs(void);
112 | void toggle_follower(uint8_t n);
113 | uint8_t get_tr(uint8_t n);
114 | void clock_set(uint32_t n);
115 | void clock_set_tr(uint32_t n, uint8_t phase);
116 |
117 | void ii_ansible(uint8_t* d, uint8_t len);
118 | void load_flash_state(void);
119 | void flash_unfresh(void);
120 |
--------------------------------------------------------------------------------
/src/update-firmware.command:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd "$(dirname "$0")"
3 | dfu-programmer at32uc3b0512 erase
4 | dfu-programmer at32uc3b0512 flash ansible.hex --suppress-bootloader-mem
5 | dfu-programmer at32uc3b0512 start
6 |
--------------------------------------------------------------------------------
/tools/flash_tools/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | Include/
3 | Lib/
4 | Scripts/
5 | tcl/
6 | pip-selfcheck.json
7 | ansible-presets.json
8 | *~
9 | *.inc
10 |
--------------------------------------------------------------------------------
/tools/flash_tools/README.md:
--------------------------------------------------------------------------------
1 | # flash_tools
2 |
3 | Gadgets for hacking on monome firmware images.
4 |
5 | # Setup
6 |
7 | Needs Python 3.5-ish.
8 |
9 | ``` bash
10 | python -m virtualenv .
11 | source Scripts/activate
12 | pip install -r requirements.pip
13 | ```
14 |
15 | # Tools
16 |
17 | ## repl - firmware file inspection
18 |
19 | ``` bash
20 | python main.py teletype repl --version 3.0.0 teletype-backup.hex
21 | ```
22 |
23 | will drop you to a Python shell. Variables in scope are:
24 |
25 | * `ffi` - A [CFFI](https://cffi.readthedocs.io/en/latest/) instance
26 | for working with C data structures, with the definitions in scope
27 | for the flash data structure of firmware/version you specify.
28 |
29 | * `ih` - An
30 | [IntelHex](https://python-intelhex.readthedocs.io/en/latest/)
31 | instance with the specified hex file loaded.
32 |
33 | * `flash` - A `bytes` with the whole contents of flash.
34 |
35 | * `nvram_data` - The C structure from flash represented as a python
36 | object (built by CFFI).
37 |
38 | * `hexdump` - A [function](https://pypi.org/project/hexdump/) for
39 | formatting bytestrings as more readable hex dumps.
40 |
41 |
42 | ## extract - convert presets from a hexdump to a JSON file
43 |
44 | Get into bootloader mode:
45 |
46 | * turn off ansible
47 | * unplug the USB A-A cable from ansible
48 | * hold down the preset/mode button while powering on ansible
49 | * plug in the USB A-A cable
50 |
51 | Dump the hex file:
52 |
53 | ``` bash
54 | dfu-programmer at32uc3b0512 read > ansible-backup.hex
55 | ```
56 |
57 | Run the script:
58 |
59 | ``` bash
60 | python main.py ansible extract --version 1.6.1 ansible-backup.hex --out ansible-preset.json
61 | ```
62 |
63 | Versions of the ansible firmware that support loading presets from a
64 | JSON file look for a file on the root of the drive named
65 | `ansible-preset.json`. The preset format from the module's flash is
66 | different depending on your firmware version, so you need to specify
67 | the firmware version the hexdump came from with the `--version` switch
68 | if different from the default (1.6.1). Support for extracting a preset
69 | from a different firmware version is straightforward to add, see
70 | e.g. schemata/v161.py.
71 |
72 |
73 |
74 | ## docdef - generate data structures describing C structs as JSON
75 |
76 | This is the flakiest one and will require some manual editing of the
77 | result, docs and cleanup forthcoming.
--------------------------------------------------------------------------------
/tools/flash_tools/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/monome/ansible/c59a42c20bf055d6c793473bbb8cdfd8b3a25bee/tools/flash_tools/commands/__init__.py
--------------------------------------------------------------------------------
/tools/flash_tools/commands/docdef/docdef_writer.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 | from contextlib import contextmanager
3 |
4 | from cffi import FFI
5 |
6 | from preset_schemata import PRESET_SCHEMATA
7 | from commands.firmware_tool import FirmwareTool
8 |
9 |
10 | class DocdefWriter(FirmwareTool):
11 | INDENT_STR = '\t'
12 | FIRMWARE_NAME = 'ansible'
13 | ROOT_TYPE = 'nvram_data_t'
14 |
15 | def __init__(self, name, firmware, version):
16 | super().__init__(firmware, version)
17 | self.name = name
18 | self.indentation = 0
19 | self.obj_depth = 0
20 | self.max_obj_depth = 0
21 | self.arr_depth = 0
22 | self.max_arr_depth = 0
23 | self.state_path = deque()
24 |
25 | self.starting_type = self.ffi.typeof(self.ROOT_TYPE)
26 |
27 | @contextmanager
28 | def indent(self, out, brackets=None):
29 | self.indentation += 1
30 | if brackets:
31 | out.write(brackets[0] + '\n')
32 | yield
33 | self.indentation -= 1
34 | self.put_indented(out, brackets[1])
35 |
36 | def put_indented(self, out, s):
37 | out.write(self.indentation * self.INDENT_STR + s)
38 |
39 | def putln(self, out, line):
40 | out.write(self.indentation * self.INDENT_STR + line + '\n')
41 |
42 | def write(self, out):
43 | self.putln(
44 | out,
45 | 'preset_section_handler_t {} = '.format(self.name)
46 | )
47 | with self.indent(out, ('{', '};\n')):
48 | self.write_object(out, self.starting_type, True)
49 | print('load_object_state_t json_object_state[{}];'.format(
50 | self.max_obj_depth + 1))
51 | print('load_array_state_t json_array_state[{}];'.format(
52 | self.max_arr_depth + 1))
53 |
54 | def write_object(self, out, ctype, params_only=False):
55 | self.putln(out, '.read = json_read_object,')
56 | self.putln(out, '.write = json_write_object,')
57 | self.putln(out, '.fresh = true,')
58 | self.putln(
59 | out,
60 | '.state = &ansible_app_object_state[{}],'.format(self.obj_depth),
61 | )
62 |
63 | with self.write_params(out, 'json_read_object_params_t'):
64 | self.putln(out, '.docdef_ct = {},'.format(len(ctype.fields)))
65 |
66 | self.put_indented(out, '.docdefs = ')
67 | with self.indent(
68 | out,
69 | (
70 | '((json_docdef_t[]) {',
71 | '}),\n'
72 | )
73 | ):
74 | for field_name, field in ctype.fields:
75 | with self.descend_object(field_name):
76 | kind_writer = self.get_writer(field.type.kind)
77 | self.put_indented(out, '')
78 | with self.indent(out, ('{', '},\n')):
79 | self.putln(out, '.name = "{}",'.format(field_name))
80 | kind_writer(out, field_name, field.type)
81 |
82 | def get_writer(self, kind):
83 | return getattr(self, 'write_{}'.format(kind))
84 |
85 | def write_primitive(self, out, field_name, ctype):
86 | self.putln(out, '.read = json_read_scalar,')
87 | if ctype.cname.startswith('uint'):
88 | self.putln(out, '.write = json_write_number,')
89 | with self.write_params(out, 'json_read_scalar_params_t', True, True):
90 | pass
91 | return
92 | if ctype.cname.startswith('int'):
93 | self.putln(out, '.write = json_write_number,')
94 | with self.write_params(out, 'json_read_scalar_params_t', True, True):
95 | self.putln(out, '.signed_val = true,')
96 | return
97 | if ctype.cname == '_Bool':
98 | self.putln(out, '.write = json_write_bool,')
99 | with self.write_params(out, 'json_read_scalar_params_t', True):
100 | pass
101 | return
102 | import pdb
103 | pdb.set_trace()
104 |
105 | def write_enum(self, out, field_name, ctype):
106 | self.putln(out, '.read = json_read_enum,'),
107 | self.putln(out, '.write = json_write_enum,'),
108 | with self.write_params(out, 'json_read_enum_params_t', True):
109 | self.put_indented(out, '.options = ')
110 | with self.indent(
111 | out,
112 | (
113 | '((const char* []) {',
114 | '}),\n',
115 | ),
116 | ):
117 | for i in range(len(ctype.elements)):
118 | self.putln(out, '"{}",'.format(ctype.elements[i]))
119 |
120 | def write_array(self, out, field_name, ctype):
121 | if ctype.item.kind == 'primitive':
122 | self.write_buffer(out, field_name, ctype)
123 | return
124 |
125 | self.putln(out, '.read = json_read_array,')
126 | self.putln(out, '.write = json_write_array,')
127 | self.putln(out, '.fresh = true,')
128 | self.putln(
129 | out, '.state = &ansible_json_array_state[{}],'.format(self.arr_depth))
130 | with self.write_params(out, 'json_read_array_params_t'):
131 | self.putln(
132 | out,
133 | '.array_len = sizeof_field({root_t}, {name}) / sizeof_field({root_t}, {name}[0]),'.format(
134 | root_t=self.ROOT_TYPE,
135 | name=self.path,
136 | ),
137 | )
138 | self.putln(
139 | out,
140 | '.item_size = sizeof_field({}, {}[0]),'.format(
141 | self.ROOT_TYPE,
142 | self.path,
143 | )
144 | )
145 |
146 | with self.descend_array():
147 | self.put_indented(out, '.item_handler = &')
148 | with self.indent(
149 | out,
150 | (
151 | '((json_docdef_t) {',
152 | '}),\n'
153 | )
154 | ):
155 | kind_writer = self.get_writer(ctype.item.kind)
156 | kind_writer(out, field_name, ctype.item)
157 |
158 | def write_buffer(self, out, field_name, ctype):
159 | self.putln(out, '.read = json_read_buffer,')
160 | self.putln(out, '.write = json_write_buffer,')
161 | self.putln(out, '.fresh = true,')
162 | self.putln(out, '.state = &json_read_buffer_state,')
163 | with self.write_params(out, 'json_read_buffer_params_t', True):
164 | pass
165 |
166 | def write_struct(self, out, field_name, ctype):
167 | self.write_object(out, ctype)
168 |
169 | @contextmanager
170 | def write_params(self, out, params_t, with_offset=False, with_size=False):
171 | self.put_indented(out, '.params = &')
172 | with self.indent(
173 | out,
174 | (
175 | '(({}) {{'.format(params_t),
176 | '}),\n'
177 | )
178 | ):
179 | if with_offset:
180 | self.putln(
181 | out,
182 | '.dst_offset = offsetof({}, {}),'.format(
183 | self.ROOT_TYPE,
184 | self.path,
185 | )
186 | )
187 | if with_size:
188 | self.putln(
189 | out,
190 | '.dst_size = sizeof_field({}, {}),'.format(
191 | self.ROOT_TYPE,
192 | self.path,
193 | )
194 | )
195 | yield
196 |
197 | @contextmanager
198 | def descend(self, s):
199 | self.state_path.append(s)
200 | yield
201 | self.state_path.pop()
202 |
203 | @contextmanager
204 | def descend_array(self):
205 | self.arr_depth += 1
206 | name = self.state_path.pop()
207 | with self.descend('{}[0]'.format(name)):
208 | yield
209 | self.state_path.append(name)
210 | if self.arr_depth > self.max_arr_depth:
211 | self.max_arr_depth = self.arr_depth
212 | self.arr_depth -= 1
213 |
214 | @contextmanager
215 | def descend_object(self, name):
216 | self.obj_depth += 1
217 | with self.descend(name):
218 | yield
219 | if self.obj_depth > self.max_obj_depth:
220 | self.max_obj_depth = self.obj_depth
221 | self.obj_depth -= 1
222 |
223 | @property
224 | def path(self):
225 | return '.'.join(self.state_path)
226 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/docdef/write_docdef.py:
--------------------------------------------------------------------------------
1 | from commands.docdef.docdef_writer import DocdefWriter
2 |
3 |
4 | def write(args):
5 | writer = DocdefWriter(args.name, args.firmware, args.version)
6 | with open(args.out, 'w') as outf:
7 | writer.write(outf)
8 | print('wrote document defintion data structure to {}'.format(args.out))
9 |
10 |
11 | def command(parser):
12 | parser.add_argument(
13 | 'name',
14 | type=str,
15 | help='name of the variable to declare',
16 | )
17 | parser.add_argument(
18 | '--version',
19 | type=str,
20 | help='firmware version to emit a preset document definition for',
21 | default='1.6.1'
22 | )
23 | parser.add_argument(
24 | '--out',
25 | type=str,
26 | help='file to write generated C code to',
27 | default='ansible_docdef.c'
28 | )
29 | parser.set_defaults(func=write)
30 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/extract/extract_presets.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import json
3 |
4 | from commands.extract.extractor import PresetExtractor
5 |
6 |
7 | def extract(args):
8 | extractor = PresetExtractor(args.firmware, args.version, args.hexfile)
9 | presets, image = extractor.extract()
10 | with open(args.out, 'w') as outf:
11 | outf.write(json.dumps(
12 | presets,
13 | indent=4 if args.pretty else None,
14 | ))
15 | print('{} preset written to {}'.format(extractor.target_version, args.out))
16 |
17 |
18 | def command(parser):
19 | parser.add_argument(
20 | 'hexfile',
21 | type=str,
22 | help='name of the hex dump file to inspect'
23 | )
24 | parser.add_argument(
25 | '--version',
26 | type=str,
27 | help='firmware version of the ansible which saved the preset',
28 | default='3.0.0'
29 | )
30 | parser.add_argument(
31 | '--target_version',
32 | type=str,
33 | help='firmware version to target with the JSON output'
34 | )
35 | parser.add_argument(
36 | '--out',
37 | type=str,
38 | help='JSON file to write the preset to',
39 | default='ansible-preset.json'
40 | )
41 | parser.add_argument(
42 | '--pretty',
43 | action='store_true',
44 | help='pretty-print the JSON output',
45 | default=False,
46 | )
47 | parser.set_defaults(func=extract)
48 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/extract/extractor.py:
--------------------------------------------------------------------------------
1 | from preset_schemata import PRESET_SCHEMATA
2 | from commands.firmware_tool import FirmwareTool
3 |
4 |
5 | class PresetExtractor(FirmwareTool):
6 | target_version = '3.0.0'
7 |
8 | def extract(self):
9 | if not self.schema.check(self.nvram_data):
10 | quit()
11 |
12 | preset = {
13 | 'meta': {
14 | 'firmware': 'ansible',
15 | 'version': self.target_version,
16 | **self.schema.meta(self.nvram_data),
17 | },
18 | 'shared': self.schema.shared(self.nvram_data),
19 | 'apps': {
20 | app: self.extract_app_state(self.nvram_data, app)
21 | for app in self.schema.app_list()
22 | },
23 | }
24 |
25 | return (preset, self.nvram_data)
26 |
27 | def extract_app_state(self, nvram_data, app_name):
28 | extractor = getattr(self.schema, 'extract_{}_state'.format(app_name))
29 | state = getattr(self.nvram_data, '{}_state'.format(app_name))
30 | return extractor(state)
31 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/firmware_tool.py:
--------------------------------------------------------------------------------
1 | import faulthandler
2 |
3 | from cffi import FFI
4 | from intelhex import IntelHex
5 |
6 | from preset_schemata import PRESET_SCHEMATA
7 |
8 |
9 | class FirmwareTool:
10 |
11 | def __init__(self, firmware, version, hexfile=None):
12 | self.ffi = FFI()
13 | try:
14 | self.schema = PRESET_SCHEMATA[firmware][version](self.ffi)
15 | except KeyError:
16 | raise NotImplementedError(
17 | "don't know how to read version {}".format(version))
18 | else:
19 | self.ffi.cdef(self.schema.cdef())
20 |
21 | if hexfile is not None:
22 | self.ih = IntelHex()
23 | self.ih.fromfile(hexfile, format='hex')
24 |
25 | # without this, the program will just silently exit if it
26 | # segfaults trying to read values from the CFFI object
27 | faulthandler.enable()
28 |
29 | self.nvram_data = self.ffi.new(
30 | '{} *'.format(self.schema.root_type()))
31 | nvram_buffer = self.ffi.buffer(self.nvram_data)
32 |
33 | # address from the ansible.sym symbol table
34 | nvram_dump = self.ih.tobinarray(
35 | self.schema.address(),
36 | self.schema.address() + len(nvram_buffer) - 1
37 | )
38 | nvram_buffer[:] = nvram_dump
39 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/repl/read_eval_print_loop.py:
--------------------------------------------------------------------------------
1 | import code
2 |
3 | from commands.firmware_tool import FirmwareTool
4 | from hexdump import hexdump
5 |
6 |
7 | class ReadEvalPrintLoop(FirmwareTool):
8 | def run(self):
9 | flash = self.ih.tobinarray(*self.ih.segments()[1])
10 | print('flash segment: 0x{:02X} bytes'.format(len(flash)))
11 | print(' nvram_data_t: 0x{:02X} bytes'.format(self.ffi.sizeof(self.nvram_data[0])))
12 | code.interact(local={
13 | 'ffi': self.ffi,
14 | 'ih': self.ih,
15 | 'flash': flash,
16 | 'nvram_data': self.nvram_data,
17 | 'hexdump': hexdump,
18 | })
19 |
--------------------------------------------------------------------------------
/tools/flash_tools/commands/repl/repl.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import json
3 |
4 | from commands.repl.read_eval_print_loop import ReadEvalPrintLoop
5 |
6 |
7 | def extract(args):
8 | repl = ReadEvalPrintLoop(args.firmware, args.version, args.hexfile)
9 | repl.run()
10 |
11 | def command(parser):
12 | parser.add_argument(
13 | 'hexfile',
14 | type=str,
15 | )
16 | parser.add_argument(
17 | '--version',
18 | type=str,
19 | help='firmware version to work with',
20 | default='1.6.1'
21 | )
22 | parser.set_defaults(func=extract)
23 |
--------------------------------------------------------------------------------
/tools/flash_tools/main.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 | from commands.extract import extract_presets
4 | from commands.docdef import write_docdef
5 | from commands.repl import repl
6 |
7 |
8 | def main():
9 | parser = argparse.ArgumentParser()
10 | parser.add_argument(
11 | 'firmware',
12 | type=str,
13 | help='name of the firmware to work with'
14 | )
15 |
16 | subparsers = parser.add_subparsers()
17 |
18 | extract_parser = subparsers.add_parser('extract')
19 | extract_presets.command(extract_parser)
20 |
21 | docdef_parser = subparsers.add_parser('docdef')
22 | write_docdef.command(docdef_parser)
23 |
24 | repl_parser = subparsers.add_parser('repl')
25 | repl.command(repl_parser)
26 |
27 | args = parser.parse_args()
28 | args.func(args)
29 |
30 |
31 | if __name__ == '__main__':
32 | main()
33 |
--------------------------------------------------------------------------------
/tools/flash_tools/preset_schema.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 | import binascii
3 | from collections import OrderedDict
4 | from functools import reduce
5 | from itertools import repeat
6 | from socket import htons, htonl
7 |
8 |
9 | class PresetSchema(ABC):
10 | def __init__(self, ffi):
11 | self.ffi = ffi
12 |
13 | @abstractmethod
14 | def check(self, nvram):
15 | pass
16 |
17 | @abstractmethod
18 | def firmware_name(self):
19 | pass
20 |
21 | def root_type(self):
22 | return 'nvram_data_t'
23 |
24 | @abstractmethod
25 | def app_list(self):
26 | pass
27 |
28 | @abstractmethod
29 | def cdef(self):
30 | pass
31 |
32 | @abstractmethod
33 | def meta(self, nvram):
34 | pass
35 |
36 | @abstractmethod
37 | def shared(self, nvram):
38 | pass
39 |
40 | def encode_bytes(self, b):
41 | return binascii.hexlify(bytes(b)).decode().upper()
42 |
43 | def encode_buffer(self, cdata):
44 | return self.encode_bytes(self.ffi.buffer(cdata))
45 |
46 | def pair(self, state, name, lam=None):
47 | mu = lam or (lambda x: x)
48 | struct_name, *rest = name.split(':', 1)
49 | json_name = rest[0] if rest else struct_name
50 | try:
51 | field = dict(self.ffi.typeof(state).fields)[struct_name]
52 | except AttributeError:
53 | field = None
54 | try:
55 | val = getattr(state, struct_name)
56 | return (json_name, mu(val, field))
57 | except Exception:
58 | print('failed at {}.{} -> "{}"'.format(state, struct_name, json_name))
59 | raise
60 |
61 | def scalar_settings(self, state, names):
62 | return OrderedDict(
63 | self.pair(state, name, self.hton)
64 | for name in names
65 | )
66 |
67 | def hton(self, val, field):
68 | # scalars always get unpacked as native byte order
69 | # so by the time they're loaded the sign has been lost
70 | f = {
71 | 'uint16_t': htons,
72 | 'int16_t': lambda x: 0 if x == 0 else htons(x & 0xFFFF) - 2**16,
73 | 'uint32_t': htonl,
74 | 'int32_t': lambda x: 0 if x == 0 else htonl(x) - 2**32,
75 | }.get(field.type.cname, lambda x: x)
76 | return f(val)
77 |
78 | def lambda_settings(self, state, lambdas_names):
79 | return OrderedDict(
80 | self.pair(state, name, lambda x, f: l(x))
81 | for name, l in lambdas_names
82 | )
83 |
84 | def array_settings(self, state, item_lambdas_names):
85 | return OrderedDict(
86 | self.pair(state, name, lambda xs, f: list(map(l, xs)))
87 | for name, l in item_lambdas_names
88 | )
89 |
90 | def enum_settings(self, state, types_names):
91 | return OrderedDict(
92 | self.pair(state, name, lambda x, f: self.enum_value(t, x, default))
93 | for name, t, default in types_names
94 | )
95 |
96 | def enum_value(self, t, val, default):
97 | enum_t = self.ffi.typeof(t)
98 | try:
99 | return enum_t.elements[val]
100 | except KeyError:
101 | return default
102 |
103 | def array_1d_settings(self, state, names):
104 | return OrderedDict(
105 | self.pair(state, name, lambda x, f: self.encode_buffer(x))
106 | for name in names
107 | )
108 |
109 | def array_2d_settings(self, state, names):
110 | return self.array_settings(
111 | state,
112 | zip(names, repeat(self.encode_buffer)),
113 | )
114 |
115 | def combine(self, *dicts):
116 | return reduce(lambda l, r: l.update(r) or l, dicts)
117 |
--------------------------------------------------------------------------------
/tools/flash_tools/preset_schemata.py:
--------------------------------------------------------------------------------
1 | from schemata.ansible import ANSIBLE_SCHEMATA
2 | from schemata.teletype import TELETYPE_SCHEMATA
3 |
4 |
5 | PRESET_SCHEMATA = {
6 | 'ansible': ANSIBLE_SCHEMATA,
7 | 'teletype': TELETYPE_SCHEMATA,
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/tools/flash_tools/requirements.pip:
--------------------------------------------------------------------------------
1 | cffi==1.11.5
2 | intelhex==2.2.1
3 | pycparser==2.19
4 | hexdump==3.3
5 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/README.md:
--------------------------------------------------------------------------------
1 | # Adding a schema definition
2 |
3 | The critical part of a schema definition class is the cdef() method,
4 | which needs to contain all the structs needed to build your target
5 | struct. The Python CFFI library can handle typedefs and macros,
6 | provided that macro definitions are constant numeric values - any type
7 | aliasing macros will have to be rewritten as typedefs.
8 |
9 | It's also important to be careful to get the packing right. In
10 | particular CFFI will always assign sizeof(long) for enums, whereas
11 | they're typically bytes for AVR32. You can change the enum fields to
12 | have a type of uint8_t, but define the enums anyway so you can access
13 | their string values. If you generate JSON document definitions for
14 | structs with enum fields this does mean you might have to clean them
15 | up by hand. It's good to check that self.ffi.sizeof('nvram_data_t')
16 | matches the size of the flash_nvram section in your ***.sym file.
17 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/__init__.py:
--------------------------------------------------------------------------------
1 | from schemata.ansible.v161 import PresetSchema_v161
2 | from schemata.ansible.v161_es import PresetSchema_v161_es
3 | from schemata.ansible.vnext import PresetSchema_vnext
4 | from schemata.ansible.v300 import PresetSchema_v300
5 |
6 | ANSIBLE_SCHEMATA = {
7 | '1.6.1': PresetSchema_v161,
8 | '1.6.1-es': PresetSchema_v161_es,
9 | 'next': PresetSchema_vnext,
10 | '3.0.0': PresetSchema_v300,
11 | }
12 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/ansible_preset_schema.py:
--------------------------------------------------------------------------------
1 | from preset_schema import PresetSchema
2 |
3 |
4 | class AnsiblePresetSchema(PresetSchema):
5 | LATEST_VERSION = '3.0.0'
6 |
7 | def firmware_name(self):
8 | return 'ansible'
9 |
10 | def address(self):
11 | # from the ansible.sym symbol table
12 | return 0x80040000
13 |
14 | def check(self, nvram):
15 | if nvram.fresh != 0x22:
16 | print("this firmware image hasn't ever been run (or is corrupt)")
17 | return False
18 | return True
19 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/v161.py:
--------------------------------------------------------------------------------
1 | from collections import OrderedDict
2 |
3 | from schemata.ansible.ansible_preset_schema import AnsiblePresetSchema
4 |
5 |
6 | class PresetSchema_v161(AnsiblePresetSchema):
7 | def app_list(self):
8 | return [
9 | 'kria',
10 | 'mp',
11 | 'levels',
12 | 'cycles',
13 | 'midi_standard',
14 | 'midi_arp',
15 | 'tt',
16 | ]
17 |
18 | def meta(self, nvram):
19 | return self.combine(
20 | self.scalar_settings(nvram.state, ['i2c_addr']),
21 | self.enum_settings(nvram.state, [
22 | ('connected', 'connected_t', 'conNONE'),
23 | ('arc_mode', 'ansible_mode_t', 'mArcLevels'),
24 | ('grid_mode', 'ansible_mode_t', 'mGridKria'),
25 | ('midi_mode', 'ansible_mode_t', 'mMidiStandard'),
26 | ('none_mode', 'ansible_mode_t', 'mTT'),
27 | ]),
28 | )
29 |
30 | def shared(self, nvram):
31 | return self.array_2d_settings(nvram, ['scale:scales'])
32 |
33 | def cdef(self):
34 | return r'''
35 | typedef uint8_t u8;
36 | typedef uint16_t u16;
37 | typedef int8_t s8;
38 | typedef int16_t s16;
39 |
40 | typedef enum {
41 | conNONE,
42 | conARC,
43 | conGRID,
44 | conMIDI,
45 | conFLASH
46 | } connected_t;
47 |
48 | connected_t connected;
49 |
50 | typedef enum {
51 | mArcLevels,
52 | mArcCycles,
53 | mGridKria,
54 | mGridMP,
55 | mMidiStandard,
56 | mMidiArp,
57 | mTT
58 | } ansible_mode_t;
59 |
60 |
61 |
62 | # define GRID_PRESETS 8
63 |
64 | # define KRIA_NUM_TRACKS 4
65 | # define KRIA_NUM_PARAMS 7
66 | # define KRIA_NUM_PATTERNS 16
67 |
68 | typedef struct {
69 | u8 tr[16];
70 | u8 oct[16];
71 | u8 note[16];
72 | u8 dur[16];
73 | u8 rpt[16];
74 | u8 alt_note[16];
75 | u8 glide[16];
76 |
77 | u8 p[KRIA_NUM_PARAMS][16];
78 |
79 | // u8 ptr[16];
80 | // u8 poct[16];
81 | // u8 pnote[16];
82 | // u8 pdur[16];
83 |
84 | u8 dur_mul;
85 |
86 | u8 lstart[KRIA_NUM_PARAMS];
87 | u8 lend[KRIA_NUM_PARAMS];
88 | u8 llen[KRIA_NUM_PARAMS];
89 | u8 lswap[KRIA_NUM_PARAMS];
90 | u8 tmul[KRIA_NUM_PARAMS];
91 | } kria_track;
92 |
93 | typedef struct {
94 | kria_track t[4];
95 | u8 scale;
96 | } kria_pattern;
97 |
98 | typedef struct {
99 | kria_pattern p[KRIA_NUM_PATTERNS];
100 | uint8_t pattern;
101 | uint8_t meta_pat[64];
102 | uint8_t meta_steps[64];
103 | uint8_t meta_start;
104 | uint8_t meta_end;
105 | uint8_t meta_len;
106 | uint8_t meta_lswap;
107 | uint8_t glyph[8];
108 | } kria_data_t;
109 |
110 | typedef struct {
111 | uint32_t clock_period;
112 | uint8_t preset;
113 | bool note_sync;
114 | uint8_t loop_sync;
115 | uint8_t cue_div;
116 | uint8_t cue_steps;
117 | uint8_t meta;
118 | kria_data_t k[GRID_PRESETS];
119 | } kria_state_t;
120 |
121 |
122 |
123 |
124 | typedef struct {
125 | // s8 position[8]; // current position in cycle
126 | // u8 tick[8]; // position in speed countdown
127 | // u8 pushed[8]; // manual key reset
128 |
129 | u8 count[8]; // length of cycle
130 | s8 speed[8]; // speed of cycle
131 | u8 min[8];
132 | u8 max[8];
133 | u8 trigger[8];
134 | u8 toggle[8];
135 | u8 rules[8];
136 | u8 rule_dests[8];
137 | u8 sync[8]; // if true, reset dest rule to count
138 | u8 rule_dest_targets[8];
139 | u8 smin[8];
140 | u8 smax[8];
141 |
142 | u8 scale;
143 | u8 glyph[8];
144 | } mp_data_t;
145 |
146 | typedef struct {
147 | uint8_t preset;
148 | uint8_t sound;
149 | uint8_t voice_mode;
150 | mp_data_t m[GRID_PRESETS];
151 | } mp_state_t;
152 |
153 |
154 | # define ARC_NUM_PRESETS 8
155 |
156 | typedef struct {
157 | uint16_t pattern[4][16];
158 | uint8_t note[4][16];
159 | bool mode[4];
160 | bool all[4];
161 | uint8_t now;
162 | uint8_t start;
163 | int8_t len;
164 | uint8_t dir;
165 | uint8_t scale[4];
166 | uint8_t octave[4];
167 | uint16_t offset[4];
168 | uint16_t range[4];
169 | uint16_t slew[4];
170 | } levels_data_t;
171 |
172 | typedef struct {
173 | // uint32_t clock_period;
174 | uint8_t preset;
175 | levels_data_t l[ARC_NUM_PRESETS];
176 | } levels_state_t;
177 |
178 |
179 | typedef struct {
180 | uint16_t pos[4];
181 | int16_t speed[4];
182 | int8_t mult[4];
183 | uint8_t range[4];
184 | uint8_t mode;
185 | uint8_t shape;
186 | uint8_t friction;
187 | uint16_t force;
188 | uint8_t div[4];
189 | } cycles_data_t;
190 |
191 | typedef struct {
192 | // uint32_t clock_period;
193 | uint8_t preset;
194 | cycles_data_t c[ARC_NUM_PRESETS];
195 | } cycles_state_t;
196 |
197 | typedef enum {
198 | eVoicePoly = 0,
199 | eVoiceMono,
200 | eVoiceMulti,
201 | eVoiceFixed,
202 |
203 | eVoiceMAX
204 | } voicing_mode;
205 |
206 | // note, cc mappings for fixed voice mode
207 | typedef struct {
208 | u8 notes[4];
209 | u8 cc[4];
210 | } fixed_mapping_t;
211 |
212 | // standard mode values saved to nvram
213 | typedef struct {
214 | uint32_t clock_period;
215 | u8 voicing;
216 | fixed_mapping_t fixed;
217 | s16 shift; // tuning/dac offset
218 | s16 slew; // pitch cv slew (ms)
219 | } midi_standard_state_t;
220 |
221 | typedef struct {
222 | u8 fill;
223 | u8 division;
224 | s8 rotation;
225 | u8 gate;
226 | u8 steps;
227 | u8 offset;
228 |
229 | s16 slew;
230 | s16 shift;
231 | } midi_arp_player_state_t;
232 |
233 | // arp mode value saved to nvram
234 | typedef struct {
235 | uint32_t clock_period;
236 | u8 style; // NB: not using arp_style as type because enums have vairable size
237 | bool hold; // if true new notes add to chord if at least one note in chord is still held
238 | midi_arp_player_state_t p[4];
239 | } midi_arp_state_t;
240 |
241 |
242 | typedef struct {
243 | uint32_t clock_period;
244 | uint16_t tr_time[4];
245 | uint16_t cv_slew[4];
246 | } tt_state_t;
247 |
248 |
249 | typedef struct {
250 | connected_t connected;
251 | ansible_mode_t arc_mode;
252 | ansible_mode_t grid_mode;
253 | ansible_mode_t midi_mode;
254 | ansible_mode_t none_mode;
255 | uint8_t i2c_addr;
256 | } ansible_state_t;
257 |
258 |
259 | // NVRAM data structure located in the flash array.
260 | typedef const struct {
261 | uint8_t fresh;
262 | ansible_state_t state;
263 | kria_state_t kria_state;
264 | mp_state_t mp_state;
265 | levels_state_t levels_state;
266 | cycles_state_t cycles_state;
267 | midi_standard_state_t midi_standard_state;
268 | midi_arp_state_t midi_arp_state;
269 | tt_state_t tt_state;
270 | uint8_t scale[16][8];
271 | } nvram_data_t;
272 | '''
273 |
274 | def extract_kria_state(self, state):
275 | return self.combine(
276 | self.scalar_settings(state, [
277 | 'clock_period',
278 | 'preset:curr_preset',
279 | 'note_sync',
280 | 'loop_sync',
281 | 'cue_div',
282 | 'cue_steps',
283 | 'meta',
284 | ]),
285 | self.array_settings(state, [
286 | (
287 | 'k:presets',
288 | lambda preset: self.combine(
289 | self.array_settings(preset, [
290 | (
291 | 'p:patterns',
292 | lambda pattern: self.combine(
293 | self.array_settings(pattern, [
294 | (
295 | 't:tracks',
296 | lambda track: self.combine(
297 | self.array_1d_settings(track, [
298 | 'tr',
299 | 'oct',
300 | 'note',
301 | 'dur',
302 | 'rpt',
303 | ]),
304 | self.extract_rpt_bits(track),
305 | self.array_1d_settings(track, [
306 | 'alt_note',
307 | 'glide',
308 | ]),
309 | self.array_2d_settings(track, [
310 | 'p'
311 | ]),
312 | self.scalar_settings(track, [
313 | 'dur_mul'
314 | ]),
315 | self.array_1d_settings(track, [
316 | 'lstart',
317 | 'lend',
318 | 'llen',
319 | 'lswap',
320 | 'tmul',
321 | ]),
322 | ),
323 | ),
324 | ]),
325 | self.scalar_settings(pattern, ['scale']),
326 | ),
327 | ),
328 | ]),
329 | self.scalar_settings(preset, [
330 | 'pattern:curr_pattern',
331 | ]),
332 | self.array_1d_settings(preset, [
333 | 'meta_pat',
334 | 'meta_steps',
335 | ]),
336 | self.scalar_settings(preset, [
337 | 'meta_start',
338 | 'meta_end',
339 | 'meta_len',
340 | 'meta_lswap',
341 | ]),
342 | self.array_1d_settings(preset, [
343 | 'glyph',
344 | ]),
345 | ),
346 | ),
347 | ]),
348 | )
349 |
350 | def extract_rpt_bits(self, track):
351 | return OrderedDict([
352 | self.pair(
353 | track,
354 | 'rpt:rptBits',
355 | lambda xs, f: self.encode_bytes(
356 | map(lambda rpt: ~(0xFF << rpt) & 0xFF, xs)
357 | )
358 | )
359 | ])
360 |
361 | def extract_mp_state(self, state):
362 | return self.combine(
363 | self.scalar_settings(state, [
364 | 'preset:curr_preset',
365 | 'sound',
366 | 'voice_mode',
367 | ]),
368 | self.array_settings(state, [
369 | (
370 | 'm:presets',
371 | lambda preset: self.combine(
372 | self.array_1d_settings(preset, [
373 | 'count',
374 | 'speed',
375 | 'min',
376 | 'max',
377 | 'trigger',
378 | 'toggle',
379 | 'rules',
380 | 'rule_dests',
381 | 'sync',
382 | 'rule_dest_targets',
383 | 'smin',
384 | 'smax',
385 | ]),
386 | self.scalar_settings(preset, [
387 | 'scale',
388 | ]),
389 | self.array_1d_settings(preset, [
390 | 'glyph',
391 | ]),
392 | self.scalar_settings(preset, [
393 | 'scale',
394 | ]),
395 | ),
396 | )
397 | ]),
398 | )
399 |
400 | def extract_levels_state(self, state):
401 | return self.combine(
402 | self.scalar_settings(state, [
403 | 'preset:curr_preset',
404 | ]),
405 | self.array_settings(state, [
406 | (
407 | 'l:presets',
408 | lambda preset: self.combine(
409 | self.array_2d_settings(preset, [
410 | 'pattern',
411 | 'note',
412 | ]),
413 | self.array_1d_settings(preset, [
414 | 'mode',
415 | 'all',
416 | ]),
417 | self.scalar_settings(preset, [
418 | 'now',
419 | 'start',
420 | 'len',
421 | 'dir',
422 | ]),
423 | self.array_1d_settings(preset, [
424 | 'scale',
425 | 'octave',
426 | 'offset',
427 | 'range',
428 | 'slew',
429 | ]),
430 | ),
431 | ),
432 | ]),
433 | )
434 |
435 | def extract_cycles_state(self, state):
436 | return self.combine(
437 | self.scalar_settings(state, [
438 | 'preset:curr_preset',
439 | ]),
440 | self.array_settings(state, [
441 | (
442 | 'c:presets',
443 | lambda preset: self.combine(
444 | self.array_1d_settings(preset, [
445 | 'pos',
446 | 'speed',
447 | 'mult',
448 | 'range',
449 | 'div',
450 | ]),
451 | self.scalar_settings(preset, [
452 | 'mode',
453 | 'shape',
454 | 'friction',
455 | 'force',
456 | ]),
457 | ),
458 | ),
459 | ]),
460 | )
461 |
462 | def extract_midi_standard_state(self, state):
463 | return self.combine(
464 | self.scalar_settings(state, [
465 | 'clock_period',
466 | 'voicing',
467 | ]),
468 | self.lambda_settings(state, [
469 | (
470 | 'fixed',
471 | lambda f: self.array_1d_settings(f, ['notes', 'cc']),
472 | ),
473 | ]),
474 | self.scalar_settings(state, [
475 | 'shift',
476 | 'slew',
477 | ]),
478 | )
479 |
480 | def extract_midi_arp_state(self, state):
481 | return self.combine(
482 | self.scalar_settings(state, [
483 | 'clock_period',
484 | 'style',
485 | 'hold',
486 | ]),
487 | self.array_settings(state, [
488 | (
489 | 'p:players',
490 | lambda player_state: self.scalar_settings(player_state, [
491 | 'fill',
492 | 'division',
493 | 'rotation',
494 | 'gate',
495 | 'steps',
496 | 'offset',
497 | 'slew',
498 | 'shift',
499 | ]),
500 | ),
501 | ]),
502 | )
503 |
504 | def extract_tt_state(self, state):
505 | return self.combine(
506 | self.scalar_settings(state, ['clock_period']),
507 | self.array_1d_settings(state, ['tr_time', 'cv_slew']),
508 | )
509 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/v161_es.py:
--------------------------------------------------------------------------------
1 | from schemata.ansible.v161 import PresetSchema_v161
2 |
3 |
4 | class PresetSchema_v161_es(PresetSchema_v161):
5 | def app_list(self):
6 | return [
7 | *super().app_list(),
8 | 'es',
9 | ]
10 |
11 | def cdef(self):
12 | return r'''
13 | typedef uint8_t u8;
14 | typedef uint16_t u16;
15 | typedef uint32_t u32;
16 | typedef int8_t s8;
17 | typedef int16_t s16;
18 |
19 | typedef enum {
20 | conNONE,
21 | conARC,
22 | conGRID,
23 | conMIDI,
24 | conFLASH
25 | } connected_t;
26 |
27 | connected_t connected;
28 |
29 | typedef enum {
30 | mArcLevels,
31 | mArcCycles,
32 | mGridKria,
33 | mGridMP,
34 | mGridES,
35 | mMidiStandard,
36 | mMidiArp,
37 | mTT
38 | } ansible_mode_t;
39 |
40 | typedef struct {
41 | connected_t connected;
42 | ansible_mode_t arc_mode;
43 | ansible_mode_t grid_mode;
44 | ansible_mode_t midi_mode;
45 | ansible_mode_t none_mode;
46 | uint8_t i2c_addr;
47 | } ansible_state_t;
48 |
49 | #define GRID_PRESETS 8
50 |
51 | #define KRIA_NUM_TRACKS 4
52 | #define KRIA_NUM_PARAMS 7
53 | #define KRIA_NUM_PATTERNS 16
54 |
55 | #define ES_EVENTS_PER_PATTERN 128
56 | #define ES_EDGE_PATTERN 0
57 | #define ES_EDGE_FIXED 1
58 | #define ES_EDGE_DRONE 2
59 |
60 | typedef struct {
61 | u8 tr[16];
62 | u8 oct[16];
63 | u8 note[16];
64 | u8 dur[16];
65 | u8 rpt[16];
66 | u8 alt_note[16];
67 | u8 glide[16];
68 |
69 | u8 p[KRIA_NUM_PARAMS][16];
70 |
71 | // u8 ptr[16];
72 | // u8 poct[16];
73 | // u8 pnote[16];
74 | // u8 pdur[16];
75 |
76 | u8 dur_mul;
77 |
78 | u8 lstart[KRIA_NUM_PARAMS];
79 | u8 lend[KRIA_NUM_PARAMS];
80 | u8 llen[KRIA_NUM_PARAMS];
81 | u8 lswap[KRIA_NUM_PARAMS];
82 | u8 tmul[KRIA_NUM_PARAMS];
83 | } kria_track;
84 |
85 | typedef struct {
86 | kria_track t[4];
87 | u8 scale;
88 | } kria_pattern;
89 |
90 | typedef struct {
91 | kria_pattern p[KRIA_NUM_PATTERNS];
92 | uint8_t pattern;
93 | uint8_t meta_pat[64];
94 | uint8_t meta_steps[64];
95 | uint8_t meta_start;
96 | uint8_t meta_end;
97 | uint8_t meta_len;
98 | uint8_t meta_lswap;
99 | uint8_t glyph[8];
100 | } kria_data_t;
101 |
102 | typedef struct {
103 | uint32_t clock_period;
104 | uint8_t preset;
105 | bool note_sync;
106 | uint8_t loop_sync;
107 | uint8_t cue_div;
108 | uint8_t cue_steps;
109 | uint8_t meta;
110 | kria_data_t k[GRID_PRESETS];
111 | } kria_state_t;
112 |
113 |
114 |
115 |
116 | typedef struct {
117 | // s8 position[8]; // current position in cycle
118 | // u8 tick[8]; // position in speed countdown
119 | // u8 pushed[8]; // manual key reset
120 |
121 | u8 count[8]; // length of cycle
122 | s8 speed[8]; // speed of cycle
123 | u8 min[8];
124 | u8 max[8];
125 | u8 trigger[8];
126 | u8 toggle[8];
127 | u8 rules[8];
128 | u8 rule_dests[8];
129 | u8 sync[8]; // if true, reset dest rule to count
130 | u8 rule_dest_targets[8];
131 | u8 smin[8];
132 | u8 smax[8];
133 |
134 | u8 scale;
135 | u8 glyph[8];
136 | } mp_data_t;
137 |
138 | typedef struct {
139 | uint8_t preset;
140 | uint8_t sound;
141 | uint8_t voice_mode;
142 | mp_data_t m[GRID_PRESETS];
143 | } mp_state_t;
144 |
145 |
146 |
147 |
148 | typedef enum {
149 | es_stopped,
150 | es_armed,
151 | es_recording,
152 | es_playing
153 | } es_mode_t;
154 |
155 | typedef enum {
156 | es_main,
157 | es_patterns_held,
158 | es_patterns
159 | } es_view_t;
160 |
161 | typedef struct {
162 | u8 active;
163 | s8 x;
164 | s8 y;
165 | u32 start;
166 | u8 from_pattern;
167 | } es_note_t;
168 |
169 | typedef struct {
170 | u8 on;
171 | u8 index;
172 | u16 interval;
173 | } es_event_t;
174 |
175 | typedef struct {
176 | es_event_t e[ES_EVENTS_PER_PATTERN];
177 | u16 interval_ind;
178 | u16 length;
179 | u8 loop;
180 | u8 root_x;
181 | u8 root_y;
182 | u8 edge;
183 | u16 edge_time;
184 | u8 voices;
185 | u8 dir;
186 | u8 linearize;
187 | u8 start;
188 | u8 end;
189 | } es_pattern_t;
190 |
191 | typedef struct {
192 | u8 arp;
193 | u8 p_select;
194 | u8 voices;
195 | u8 octave;
196 | u8 scale;
197 | u16 keymap[128];
198 | es_pattern_t p[16];
199 | u8 glyph[8];
200 | } es_data_t;
201 |
202 | typedef struct {
203 | u8 preset;
204 | es_data_t e[GRID_PRESETS];
205 | } es_state_t;
206 |
207 |
208 | #define ARC_NUM_PRESETS 8
209 |
210 | typedef struct {
211 | uint16_t pattern[4][16];
212 | uint8_t note[4][16];
213 | bool mode[4];
214 | bool all[4];
215 | uint8_t now;
216 | uint8_t start;
217 | int8_t len;
218 | uint8_t dir;
219 | uint8_t scale[4];
220 | uint8_t octave[4];
221 | uint16_t offset[4];
222 | uint16_t range[4];
223 | uint16_t slew[4];
224 | } levels_data_t;
225 |
226 | typedef struct {
227 | // uint32_t clock_period;
228 | uint8_t preset;
229 | levels_data_t l[ARC_NUM_PRESETS];
230 | } levels_state_t;
231 |
232 |
233 | typedef struct {
234 | uint16_t pos[4];
235 | int16_t speed[4];
236 | int8_t mult[4];
237 | uint8_t range[4];
238 | uint8_t mode;
239 | uint8_t shape;
240 | uint8_t friction;
241 | uint16_t force;
242 | uint8_t div[4];
243 | } cycles_data_t;
244 |
245 | typedef struct {
246 | // uint32_t clock_period;
247 | uint8_t preset;
248 | cycles_data_t c[ARC_NUM_PRESETS];
249 | } cycles_state_t;
250 |
251 | typedef enum {
252 | eVoicePoly = 0,
253 | eVoiceMono,
254 | eVoiceMulti,
255 | eVoiceFixed,
256 |
257 | eVoiceMAX
258 | } voicing_mode;
259 |
260 | // note, cc mappings for fixed voice mode
261 | typedef struct {
262 | u8 notes[4];
263 | u8 cc[4];
264 | } fixed_mapping_t;
265 |
266 | // standard mode values saved to nvram
267 | typedef struct {
268 | uint32_t clock_period;
269 | u8 voicing;
270 | fixed_mapping_t fixed;
271 | s16 shift; // tuning/dac offset
272 | s16 slew; // pitch cv slew (ms)
273 | } midi_standard_state_t;
274 |
275 | typedef struct {
276 | u8 fill;
277 | u8 division;
278 | s8 rotation;
279 | u8 gate;
280 | u8 steps;
281 | u8 offset;
282 |
283 | s16 slew;
284 | s16 shift;
285 | } midi_arp_player_state_t;
286 |
287 | // arp mode value saved to nvram
288 | typedef struct {
289 | uint32_t clock_period;
290 | u8 style; // NB: not using arp_style as type because enums have vairable size
291 | bool hold; // if true new notes add to chord if at least one note in chord is still held
292 | midi_arp_player_state_t p[4];
293 | } midi_arp_state_t;
294 |
295 |
296 | typedef struct {
297 | uint32_t clock_period;
298 | uint16_t tr_time[4];
299 | uint16_t cv_slew[4];
300 | } tt_state_t;
301 |
302 |
303 | // NVRAM data structure located in the flash array.
304 | typedef const struct {
305 | uint8_t fresh;
306 | ansible_state_t state;
307 | kria_state_t kria_state;
308 | mp_state_t mp_state;
309 | es_state_t es_state;
310 | levels_state_t levels_state;
311 | cycles_state_t cycles_state;
312 | midi_standard_state_t midi_standard_state;
313 | midi_arp_state_t midi_arp_state;
314 | tt_state_t tt_state;
315 | uint8_t scale[16][8];
316 | } nvram_data_t;
317 | '''
318 |
319 | def extract_es_state(self, state):
320 | return {
321 | 'curr_preset': state.preset,
322 | 'presets': [
323 | self.combine(
324 | self.scalar_settings(preset, [
325 | 'arp',
326 | 'p_select',
327 | 'voices',
328 | 'octave',
329 | 'scale',
330 | ]),
331 | self.array_1d_settings(preset, [
332 | 'keymap',
333 | 'glyph',
334 | ]),
335 | {
336 | 'patterns': [
337 | self.combine(
338 | self.scalar_settings(pattern, [
339 | 'interval_ind',
340 | 'length',
341 | 'loop',
342 | 'root_x',
343 | 'root_y',
344 | 'edge',
345 | 'edge_time',
346 | 'voices',
347 | 'dir',
348 | 'linearize',
349 | 'start',
350 | 'end',
351 | ]),
352 | {
353 | 'events': [
354 | self.scalar_settings(event, [
355 | 'on',
356 | 'index',
357 | 'interval',
358 | ])
359 | for event in pattern.e
360 | ]
361 | }
362 | )
363 | for pattern in preset.p
364 | ]
365 | }
366 | )
367 | for preset in state.e
368 | ]
369 | }
370 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/v300.py:
--------------------------------------------------------------------------------
1 | from schemata.ansible.v161 import PresetSchema_v161
2 |
3 |
4 | class PresetSchema_v300(PresetSchema_v161):
5 | def app_list(self):
6 | return [
7 | 'kria',
8 | 'mp',
9 | 'es',
10 | 'levels',
11 | 'cycles',
12 | 'midi_standard',
13 | 'midi_arp',
14 | 'tt',
15 | ]
16 |
17 | def cdef(self):
18 | return r'''
19 | typedef uint8_t u8;
20 | typedef uint16_t u16;
21 | typedef uint32_t u32;
22 | typedef int8_t s8;
23 | typedef int16_t s16;
24 |
25 | typedef enum {
26 | conNONE,
27 | conARC,
28 | conGRID,
29 | conMIDI,
30 | conFLASH
31 | } connected_t;
32 |
33 | connected_t connected;
34 |
35 | typedef enum {
36 | mArcLevels,
37 | mArcCycles,
38 | mGridKria,
39 | mGridMP,
40 | mGridES,
41 | mMidiStandard,
42 | mMidiArp,
43 | mTT,
44 | } ansible_mode_t;
45 |
46 | typedef enum {
47 | krDirForward = 0,
48 | krDirReverse = 1,
49 | krDirTriangle = 2,
50 | krDirDrunk = 3,
51 | krDirRandom = 4,
52 | } kria_direction;
53 |
54 |
55 | #define GRID_PRESETS 8
56 |
57 | #define KRIA_NUM_TRACKS 4
58 | #define KRIA_NUM_PARAMS 7
59 | #define KRIA_NUM_PATTERNS 16
60 |
61 | #define ES_EVENTS_PER_PATTERN 128
62 | #define ES_EDGE_PATTERN 0
63 | #define ES_EDGE_FIXED 1
64 | #define ES_EDGE_DRONE 2
65 |
66 |
67 | typedef struct {
68 | u8 tr[16];
69 | s8 oct[16];
70 | u8 note[16];
71 | u8 dur[16];
72 | u8 rpt[16];
73 | u8 rptBits[16];
74 | u8 alt_note[16];
75 | u8 glide[16];
76 |
77 | u8 p[KRIA_NUM_PARAMS][16];
78 |
79 | // u8 ptr[16];
80 | // u8 poct[16];
81 | // u8 pnote[16];
82 | // u8 pdur[16];
83 |
84 | u8 dur_mul;
85 | kria_direction direction;
86 | u8 advancing[KRIA_NUM_PARAMS];
87 | u8 octshift;
88 |
89 | u8 lstart[KRIA_NUM_PARAMS];
90 | u8 lend[KRIA_NUM_PARAMS];
91 | u8 llen[KRIA_NUM_PARAMS];
92 | u8 lswap[KRIA_NUM_PARAMS];
93 | u8 tmul[KRIA_NUM_PARAMS];
94 |
95 | bool tt_clocked;
96 | bool trigger_clocked;
97 | } kria_track;
98 |
99 | typedef struct {
100 | kria_track t[4];
101 | u8 scale;
102 | } kria_pattern;
103 |
104 | typedef struct {
105 | kria_pattern p[KRIA_NUM_PATTERNS];
106 | uint8_t pattern;
107 | uint8_t meta_pat[64];
108 | uint8_t meta_steps[64];
109 | uint8_t meta_start;
110 | uint8_t meta_end;
111 | uint8_t meta_len;
112 | uint8_t meta_lswap;
113 | uint8_t glyph[8];
114 | } kria_data_t;
115 |
116 | typedef enum {
117 | krSyncNone = 0x00,
118 | krSyncTimeDiv = 0x01,
119 | } kria_sync_mode_t;
120 |
121 | typedef struct {
122 | uint32_t clock_period;
123 | uint8_t sync_mode; // enum kria_sync_mode_t
124 | uint8_t preset;
125 | bool note_sync;
126 | uint8_t loop_sync;
127 | bool note_div_sync;
128 | uint8_t div_sync;
129 | uint8_t cue_div;
130 | uint8_t cue_steps;
131 | uint8_t meta;
132 | kria_data_t k[GRID_PRESETS];
133 | } kria_state_t;
134 |
135 |
136 | typedef struct {
137 | // s8 position[8]; // current position in cycle
138 | // u8 tick[8]; // position in speed countdown
139 | // u8 pushed[8]; // manual key reset
140 |
141 | u8 count[8]; // length of cycle
142 | s8 speed[8]; // speed of cycle
143 | u8 min[8];
144 | u8 max[8];
145 | u8 trigger[8];
146 | u8 toggle[8];
147 | u8 rules[8];
148 | u8 rule_dests[8];
149 | u8 sync[8]; // if true, reset dest rule to count
150 | u8 rule_dest_targets[8];
151 | u8 smin[8];
152 | u8 smax[8];
153 |
154 | u8 scale;
155 | u8 glyph[8];
156 | } mp_data_t;
157 |
158 | typedef struct {
159 | uint8_t preset;
160 | uint8_t sound;
161 | uint8_t voice_mode;
162 | mp_data_t m[GRID_PRESETS];
163 | } mp_state_t;
164 |
165 |
166 | typedef enum {
167 | es_stopped,
168 | es_armed,
169 | es_recording,
170 | es_playing
171 | } es_mode_t;
172 |
173 | typedef enum {
174 | es_main,
175 | es_patterns_held,
176 | es_patterns
177 | } es_view_t;
178 |
179 | typedef struct {
180 | u8 active;
181 | s8 x;
182 | s8 y;
183 | u32 start;
184 | u8 from_pattern;
185 | } es_note_t;
186 |
187 | typedef struct {
188 | u8 on;
189 | u8 index;
190 | u16 interval;
191 | } es_event_t;
192 |
193 | typedef struct {
194 | es_event_t e[ES_EVENTS_PER_PATTERN];
195 | u16 interval_ind;
196 | u16 length;
197 | u8 loop;
198 | u8 root_x;
199 | u8 root_y;
200 | u8 edge;
201 | u16 edge_time;
202 | u8 voices;
203 | u8 dir;
204 | u8 linearize;
205 | u8 start;
206 | u8 end;
207 | } es_pattern_t;
208 |
209 | typedef struct {
210 | u8 arp;
211 | u8 p_select;
212 | u8 voices;
213 | u8 octave;
214 | u8 scale;
215 | u16 keymap[128];
216 | es_pattern_t p[16];
217 | u8 glyph[8];
218 | } es_data_t;
219 |
220 | typedef struct {
221 | u8 preset;
222 | es_data_t e[GRID_PRESETS];
223 | } es_state_t;
224 |
225 |
226 | # define ARC_NUM_PRESETS 8
227 |
228 | typedef struct {
229 | uint16_t pattern[4][16];
230 | uint8_t note[4][16];
231 | bool mode[4];
232 | bool all[4];
233 | uint8_t now;
234 | uint8_t start;
235 | int8_t len;
236 | uint8_t dir;
237 | uint8_t scale[4];
238 | uint8_t octave[4];
239 | uint16_t offset[4];
240 | uint16_t range[4];
241 | uint16_t slew[4];
242 | } levels_data_t;
243 |
244 | typedef struct {
245 | // uint32_t clock_period;
246 | uint8_t preset;
247 | levels_data_t l[ARC_NUM_PRESETS];
248 | } levels_state_t;
249 |
250 |
251 | typedef struct {
252 | uint16_t pos[4];
253 | int16_t speed[4];
254 | int8_t mult[4];
255 | uint8_t range[4];
256 | uint8_t mode;
257 | uint8_t shape;
258 | uint8_t friction;
259 | uint16_t force;
260 | uint8_t div[4];
261 | } cycles_data_t;
262 |
263 | typedef struct {
264 | // uint32_t clock_period;
265 | uint8_t preset;
266 | cycles_data_t c[ARC_NUM_PRESETS];
267 | } cycles_state_t;
268 |
269 | typedef enum {
270 | eVoicePoly = 0,
271 | eVoiceMono,
272 | eVoiceMulti,
273 | eVoiceFixed,
274 |
275 | eVoiceMAX
276 | } voicing_mode;
277 |
278 | // note, cc mappings for fixed voice mode
279 | typedef struct {
280 | u8 notes[4];
281 | u8 cc[4];
282 | } fixed_mapping_t;
283 |
284 | // standard mode values saved to nvram
285 | typedef struct {
286 | uint32_t clock_period;
287 | u8 voicing;
288 | fixed_mapping_t fixed;
289 | s16 shift; // tuning/dac offset
290 | s16 slew; // pitch cv slew (ms)
291 | } midi_standard_state_t;
292 |
293 | typedef struct {
294 | u8 fill;
295 | u8 division;
296 | s8 rotation;
297 | u8 gate;
298 | u8 steps;
299 | u8 offset;
300 |
301 | s16 slew;
302 | s16 shift;
303 | } midi_arp_player_state_t;
304 |
305 | // arp mode value saved to nvram
306 | typedef struct {
307 | uint32_t clock_period;
308 | u8 style; // NB: not using arp_style as type because enums have vairable size
309 | bool hold; // if true new notes add to chord if at least one note in chord is still held
310 | midi_arp_player_state_t p[4];
311 | } midi_arp_state_t;
312 |
313 |
314 | typedef struct {
315 | uint32_t clock_period;
316 | uint16_t tr_time[4];
317 | uint16_t cv_slew[4];
318 | } tt_state_t;
319 |
320 |
321 | #define I2C_FOLLOWER_COUNT 3
322 |
323 | struct i2c_follower_t;
324 |
325 | typedef void(*ii_u8_cb)(struct i2c_follower_t* follower, uint8_t track, uint8_t param);
326 | typedef void(*ii_s8_cb)(struct i2c_follower_t* follower, uint8_t track, int8_t param);
327 | typedef void(*ii_u16_cb)(struct i2c_follower_t* follower, uint8_t track, uint16_t param);
328 |
329 | typedef struct i2c_follower_t {
330 | uint8_t addr;
331 | bool active;
332 | uint8_t track_en;
333 | int8_t oct;
334 |
335 | u32 init; // ii_u8_cb
336 | u32 mode; // ii_u8_cb
337 | u32 tr; // ii_u8_cb
338 | u32 mute; // ii_u8_cb
339 |
340 | u32 cv; // ii_u16_cb
341 | u32 slew; // ii_u16_cb
342 | u32 octave; // ii_s8_cb
343 |
344 | uint8_t mode_ct;
345 | uint8_t active_mode;
346 | } i2c_follower_t;
347 |
348 |
349 | typedef struct {
350 | connected_t connected;
351 | ansible_mode_t arc_mode;
352 | ansible_mode_t grid_mode;
353 | ansible_mode_t midi_mode;
354 | ansible_mode_t none_mode;
355 | u8 i2c_addr;
356 | u8 grid_varibrightness;
357 | i2c_follower_t followers[I2C_FOLLOWER_COUNT];
358 | } ansible_state_t;
359 |
360 |
361 | // NVRAM data structure located in the flash array.
362 | typedef const struct {
363 | uint8_t fresh;
364 | ansible_state_t state;
365 | kria_state_t kria_state;
366 | mp_state_t mp_state;
367 | es_state_t es_state;
368 | levels_state_t levels_state;
369 | cycles_state_t cycles_state;
370 | midi_standard_state_t midi_standard_state;
371 | midi_arp_state_t midi_arp_state;
372 | tt_state_t tt_state;
373 | uint8_t scale[16][8];
374 | uint16_t tuning_table[4][120];
375 | } nvram_data_t;
376 | '''
377 |
378 | def meta(self, nvram):
379 | return self.combine(
380 | self.scalar_settings(
381 | nvram.state, ['i2c_addr', 'grid_varibrightness']),
382 | self.array_settings(nvram.state, [
383 | (
384 | 'followers',
385 | lambda follower: self.combine(
386 | self.scalar_settings(follower, [
387 | 'active',
388 | 'track_en',
389 | 'oct',
390 | 'active_mode',
391 | ])
392 | )
393 | )
394 | ]),
395 | self.enum_settings(nvram.state, [
396 | ('connected', 'connected_t', 'conNONE'),
397 | ('arc_mode', 'ansible_mode_t', 'mArcLevels'),
398 | ('grid_mode', 'ansible_mode_t', 'mGridKria'),
399 | ('midi_mode', 'ansible_mode_t', 'mMidiStandard'),
400 | ('none_mode', 'ansible_mode_t', 'mTT'),
401 | ]),
402 | )
403 |
404 | def shared(self, nvram):
405 | return self.combine(
406 | self.array_2d_settings(nvram, ['scale:scales']),
407 | self.array_2d_settings(nvram, ['tuning_table'])
408 | )
409 |
410 | def extract_kria_state(self, state):
411 | return self.combine(
412 | self.scalar_settings(state, [
413 | 'clock_period',
414 | 'preset:curr_preset',
415 | 'sync_mode',
416 | 'note_sync',
417 | 'loop_sync',
418 | 'note_div_sync',
419 | 'div_sync',
420 | 'cue_div',
421 | 'cue_steps',
422 | 'meta',
423 | ]),
424 | self.array_settings(state, [
425 | (
426 | 'k:presets',
427 | lambda preset: self.combine(
428 | self.array_settings(preset, [
429 | (
430 | 'p:patterns',
431 | lambda pattern: self.combine(
432 | self.array_settings(pattern, [
433 | (
434 | 't:tracks',
435 | lambda track: self.combine(
436 | self.array_1d_settings(track, [
437 | 'tr',
438 | 'oct',
439 | 'note',
440 | 'dur',
441 | 'rpt',
442 | 'rptBits',
443 | 'alt_note',
444 | 'glide',
445 | ]),
446 | self.array_2d_settings(track, [
447 | 'p'
448 | ]),
449 | self.scalar_settings(track, [
450 | 'dur_mul',
451 | 'direction',
452 | ]),
453 | self.array_1d_settings(track, [
454 | 'advancing',
455 | ]),
456 | self.scalar_settings(track, [
457 | 'octshift',
458 | ]),
459 | self.array_1d_settings(track, [
460 | 'lstart',
461 | 'lend',
462 | 'llen',
463 | 'lswap',
464 | 'tmul',
465 | ]),
466 | self.scalar_settings(track, [
467 | 'tt_clocked',
468 | 'trigger_clocked'
469 | ]),
470 | ),
471 | ),
472 | ]),
473 | self.scalar_settings(pattern, ['scale']),
474 | ),
475 | ),
476 | ]),
477 | self.scalar_settings(preset, [
478 | 'pattern:curr_pattern',
479 | ]),
480 | self.array_1d_settings(preset, [
481 | 'meta_pat',
482 | 'meta_steps',
483 | ]),
484 | self.scalar_settings(preset, [
485 | 'meta_start',
486 | 'meta_end',
487 | 'meta_len',
488 | 'meta_lswap',
489 | ]),
490 | self.array_1d_settings(preset, [
491 | 'glyph',
492 | ]),
493 | ),
494 | ),
495 | ]),
496 | )
497 |
498 | def extract_es_state(self, state):
499 | return {
500 | 'curr_preset': state.preset,
501 | 'presets': [
502 | self.combine(
503 | self.scalar_settings(preset, [
504 | 'arp',
505 | 'p_select',
506 | 'voices',
507 | 'octave',
508 | 'scale',
509 | ]),
510 | self.array_1d_settings(preset, [
511 | 'keymap',
512 | 'glyph',
513 | ]),
514 | {
515 | 'patterns': [
516 | self.combine(
517 | {
518 | 'events': [
519 | self.scalar_settings(event, [
520 | 'on',
521 | 'index',
522 | 'interval',
523 | ])
524 | for event in pattern.e
525 | ]
526 | },
527 | self.scalar_settings(pattern, [
528 | 'interval_ind',
529 | 'length',
530 | 'loop',
531 | 'root_x',
532 | 'root_y',
533 | 'edge',
534 | 'edge_time',
535 | 'voices',
536 | 'dir',
537 | 'linearize',
538 | 'start',
539 | 'end',
540 | ]),
541 | )
542 | for pattern in preset.p
543 | ]
544 | }
545 | )
546 | for preset in state.e
547 | ]
548 | }
549 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/ansible/vnext.py:
--------------------------------------------------------------------------------
1 | from schemata.ansible.v161 import PresetSchema_v161
2 |
3 |
4 | class PresetSchema_vnext(PresetSchema_v161):
5 | def app_list(self):
6 | return [
7 | 'levels',
8 | 'cycles',
9 | 'kria',
10 | 'mp',
11 | 'es',
12 | 'midi_standard',
13 | 'midi_arp',
14 | 'tt',
15 | ]
16 |
17 | def cdef(self):
18 | return r'''
19 | typedef uint8_t u8;
20 | typedef uint16_t u16;
21 | typedef uint32_t u32;
22 | typedef int8_t s8;
23 | typedef int16_t s16;
24 |
25 | typedef enum {
26 | conNONE,
27 | conARC,
28 | conGRID,
29 | conMIDI,
30 | conFLASH
31 | } connected_t;
32 |
33 | connected_t connected;
34 |
35 | typedef enum {
36 | mArcLevels,
37 | mArcCycles,
38 | mGridKria,
39 | mGridMP,
40 | mGridES,
41 | mMidiStandard,
42 | mMidiArp,
43 | mTT,
44 | } ansible_mode_t;
45 |
46 | typedef enum {
47 | krDirForward = 0,
48 | krDirReverse = 1,
49 | krDirTriangle = 2,
50 | krDirDrunk = 3,
51 | krDirRandom = 4,
52 | } kria_direction;
53 |
54 |
55 | #define GRID_PRESETS 8
56 |
57 | #define KRIA_NUM_TRACKS 4
58 | #define KRIA_NUM_PARAMS 7
59 | #define KRIA_NUM_PATTERNS 16
60 |
61 | #define ES_EVENTS_PER_PATTERN 128
62 | #define ES_EDGE_PATTERN 0
63 | #define ES_EDGE_FIXED 1
64 | #define ES_EDGE_DRONE 2
65 |
66 |
67 | typedef struct {
68 | u8 tr[16];
69 | u8 oct[16];
70 | u8 note[16];
71 | u8 dur[16];
72 | u8 rpt[16];
73 | u8 rptBits[16];
74 | u8 alt_note[16];
75 | u8 glide[16];
76 |
77 | u8 p[KRIA_NUM_PARAMS][16];
78 |
79 | // u8 ptr[16];
80 | // u8 poct[16];
81 | // u8 pnote[16];
82 | // u8 pdur[16];
83 |
84 | u8 dur_mul;
85 | kria_direction direction;
86 | u8 advancing[KRIA_NUM_PARAMS];
87 | u8 octshift;
88 |
89 | u8 lstart[KRIA_NUM_PARAMS];
90 | u8 lend[KRIA_NUM_PARAMS];
91 | u8 llen[KRIA_NUM_PARAMS];
92 | u8 lswap[KRIA_NUM_PARAMS];
93 | u8 tmul[KRIA_NUM_PARAMS];
94 |
95 | bool tt_clocked;
96 | } kria_track;
97 |
98 | typedef struct {
99 | kria_track t[4];
100 | u8 scale;
101 | } kria_pattern;
102 |
103 | typedef struct {
104 | kria_pattern p[KRIA_NUM_PATTERNS];
105 | uint8_t pattern;
106 | uint8_t meta_pat[64];
107 | uint8_t meta_steps[64];
108 | uint8_t meta_start;
109 | uint8_t meta_end;
110 | uint8_t meta_len;
111 | uint8_t meta_lswap;
112 | uint8_t glyph[8];
113 | } kria_data_t;
114 |
115 | typedef struct {
116 | uint32_t clock_period;
117 | uint8_t preset;
118 | bool note_sync;
119 | uint8_t loop_sync;
120 | uint8_t cue_div;
121 | uint8_t cue_steps;
122 | uint8_t meta;
123 | kria_data_t k[GRID_PRESETS];
124 | } kria_state_t;
125 |
126 |
127 | typedef struct {
128 | // s8 position[8]; // current position in cycle
129 | // u8 tick[8]; // position in speed countdown
130 | // u8 pushed[8]; // manual key reset
131 |
132 | u8 count[8]; // length of cycle
133 | s8 speed[8]; // speed of cycle
134 | u8 min[8];
135 | u8 max[8];
136 | u8 trigger[8];
137 | u8 toggle[8];
138 | u8 rules[8];
139 | u8 rule_dests[8];
140 | u8 sync[8]; // if true, reset dest rule to count
141 | u8 rule_dest_targets[8];
142 | u8 smin[8];
143 | u8 smax[8];
144 |
145 | u8 scale;
146 | u8 glyph[8];
147 | } mp_data_t;
148 |
149 | typedef struct {
150 | uint8_t preset;
151 | uint8_t sound;
152 | uint8_t voice_mode;
153 | mp_data_t m[GRID_PRESETS];
154 | } mp_state_t;
155 |
156 |
157 | typedef enum {
158 | es_stopped,
159 | es_armed,
160 | es_recording,
161 | es_playing
162 | } es_mode_t;
163 |
164 | typedef enum {
165 | es_main,
166 | es_patterns_held,
167 | es_patterns
168 | } es_view_t;
169 |
170 | typedef struct {
171 | u8 active;
172 | s8 x;
173 | s8 y;
174 | u32 start;
175 | u8 from_pattern;
176 | } es_note_t;
177 |
178 | typedef struct {
179 | u8 on;
180 | u8 index;
181 | u16 interval;
182 | } es_event_t;
183 |
184 | typedef struct {
185 | es_event_t e[ES_EVENTS_PER_PATTERN];
186 | u16 interval_ind;
187 | u16 length;
188 | u8 loop;
189 | u8 root_x;
190 | u8 root_y;
191 | u8 edge;
192 | u16 edge_time;
193 | u8 voices;
194 | u8 dir;
195 | u8 linearize;
196 | u8 start;
197 | u8 end;
198 | } es_pattern_t;
199 |
200 | typedef struct {
201 | u8 arp;
202 | u8 p_select;
203 | u8 voices;
204 | u8 octave;
205 | u8 scale;
206 | u8 keymap[256];
207 | es_pattern_t p[16];
208 | u8 glyph[8];
209 | } es_data_t;
210 |
211 | typedef struct {
212 | u8 preset;
213 | es_data_t e[GRID_PRESETS];
214 | } es_state_t;
215 |
216 |
217 | # define ARC_NUM_PRESETS 8
218 |
219 | typedef struct {
220 | uint16_t pattern[4][16];
221 | uint8_t note[4][16];
222 | bool mode[4];
223 | bool all[4];
224 | uint8_t now;
225 | uint8_t start;
226 | int8_t len;
227 | uint8_t dir;
228 | uint8_t scale[4];
229 | uint8_t octave[4];
230 | uint16_t offset[4];
231 | uint16_t range[4];
232 | uint16_t slew[4];
233 | } levels_data_t;
234 |
235 | typedef struct {
236 | // uint32_t clock_period;
237 | uint8_t preset;
238 | levels_data_t l[ARC_NUM_PRESETS];
239 | } levels_state_t;
240 |
241 |
242 | typedef struct {
243 | uint16_t pos[4];
244 | int16_t speed[4];
245 | int8_t mult[4];
246 | uint8_t range[4];
247 | uint8_t mode;
248 | uint8_t shape;
249 | uint8_t friction;
250 | uint16_t force;
251 | uint8_t div[4];
252 | } cycles_data_t;
253 |
254 | typedef struct {
255 | // uint32_t clock_period;
256 | uint8_t preset;
257 | cycles_data_t c[ARC_NUM_PRESETS];
258 | } cycles_state_t;
259 |
260 | typedef enum {
261 | eVoicePoly = 0,
262 | eVoiceMono,
263 | eVoiceMulti,
264 | eVoiceFixed,
265 |
266 | eVoiceMAX
267 | } voicing_mode;
268 |
269 | // note, cc mappings for fixed voice mode
270 | typedef struct {
271 | u8 notes[4];
272 | u8 cc[4];
273 | } fixed_mapping_t;
274 |
275 | // standard mode values saved to nvram
276 | typedef struct {
277 | uint32_t clock_period;
278 | u8 voicing;
279 | fixed_mapping_t fixed;
280 | s16 shift; // tuning/dac offset
281 | s16 slew; // pitch cv slew (ms)
282 | } midi_standard_state_t;
283 |
284 | typedef struct {
285 | u8 fill;
286 | u8 division;
287 | s8 rotation;
288 | u8 gate;
289 | u8 steps;
290 | u8 offset;
291 |
292 | s16 slew;
293 | s16 shift;
294 | } midi_arp_player_state_t;
295 |
296 | // arp mode value saved to nvram
297 | typedef struct {
298 | uint32_t clock_period;
299 | u8 style; // NB: not using arp_style as type because enums have vairable size
300 | bool hold; // if true new notes add to chord if at least one note in chord is still held
301 | midi_arp_player_state_t p[4];
302 | } midi_arp_state_t;
303 |
304 |
305 | typedef struct {
306 | uint32_t clock_period;
307 | uint16_t tr_time[4];
308 | uint16_t cv_slew[4];
309 | } tt_state_t;
310 |
311 |
312 | typedef struct {
313 | connected_t connected;
314 | ansible_mode_t arc_mode;
315 | ansible_mode_t grid_mode;
316 | ansible_mode_t midi_mode;
317 | ansible_mode_t none_mode;
318 | uint8_t i2c_addr;
319 | } ansible_state_t;
320 |
321 |
322 | // NVRAM data structure located in the flash array.
323 | typedef const struct {
324 | uint8_t fresh;
325 | ansible_state_t state;
326 | kria_state_t kria_state;
327 | mp_state_t mp_state;
328 | es_state_t es_state;
329 | levels_state_t levels_state;
330 | cycles_state_t cycles_state;
331 | midi_standard_state_t midi_standard_state;
332 | midi_arp_state_t midi_arp_state;
333 | tt_state_t tt_state;
334 | uint8_t scale[16][8];
335 | } nvram_data_t;
336 | '''
337 |
338 | def extract_kria_state(self, state):
339 | return self.combine(
340 | self.scalar_settings(state, [
341 | 'clock_period',
342 | 'preset:curr_preset',
343 | 'note_sync',
344 | 'loop_sync',
345 | 'cue_div',
346 | 'cue_steps',
347 | 'meta',
348 | ]),
349 | self.array_settings(state, [
350 | (
351 | 'k:presets',
352 | lambda preset: self.combine(
353 | self.array_settings(preset, [
354 | (
355 | 'p:patterns',
356 | lambda pattern: self.combine(
357 | self.array_settings(pattern, [
358 | (
359 | 't:tracks',
360 | lambda track: self.combine(
361 | self.array_1d_settings(track, [
362 | 'tr',
363 | 'oct',
364 | 'note',
365 | 'dur',
366 | 'rpt',
367 | # 'rptBits',
368 | 'alt_note',
369 | 'glide',
370 | ]),
371 | self.array_2d_settings(track, [
372 | 'p'
373 | ]),
374 | self.scalar_settings(track, [
375 | 'dur_mul',
376 | 'direction',
377 | ]),
378 | self.array_1d_settings(track, [
379 | 'advancing',
380 | ]),
381 | self.scalar_settings(track, [
382 | 'octshift',
383 | ]),
384 | self.array_1d_settings(track, [
385 | 'lstart',
386 | 'lend',
387 | 'llen',
388 | 'lswap',
389 | 'tmul',
390 | ]),
391 | self.scalar_settings(track, [
392 | 'tt_clocked',
393 | ]),
394 | ),
395 | ),
396 | ]),
397 | self.scalar_settings(pattern, ['scale']),
398 | ),
399 | ),
400 | ]),
401 | self.scalar_settings(preset, [
402 | 'pattern:curr_pattern',
403 | ]),
404 | self.array_1d_settings(preset, [
405 | 'meta_pat',
406 | 'meta_steps',
407 | ]),
408 | self.scalar_settings(preset, [
409 | 'meta_start',
410 | 'meta_end',
411 | 'meta_len',
412 | 'meta_lswap',
413 | ]),
414 | self.array_1d_settings(preset, [
415 | 'glyph',
416 | ]),
417 | ),
418 | ),
419 | ]),
420 | )
421 |
422 | def extract_es_state(self, state):
423 | return {
424 | 'curr_preset': state.preset,
425 | 'presets': [
426 | self.combine(
427 | self.scalar_settings(preset, [
428 | 'arp',
429 | 'p_select',
430 | 'voices',
431 | 'octave',
432 | 'scale',
433 | ]),
434 | self.array_1d_settings(preset, [
435 | 'keymap',
436 | 'glyph',
437 | ]),
438 | {
439 | 'patterns': [
440 | self.combine(
441 | self.scalar_settings(pattern, [
442 | 'interval_ind',
443 | 'length',
444 | 'loop',
445 | 'root_x',
446 | 'root_y',
447 | 'edge',
448 | 'edge_time',
449 | 'voices',
450 | 'dir',
451 | 'linearize',
452 | 'start',
453 | 'end',
454 | ]),
455 | {
456 | 'events': [
457 | self.scalar_settings(event, [
458 | 'on',
459 | 'index',
460 | 'interval',
461 | ])
462 | for event in pattern.e
463 | ]
464 | }
465 | )
466 | for pattern in preset.p
467 | ]
468 | }
469 | )
470 | for preset in state.e
471 | ]
472 | }
473 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/teletype/__init__.py:
--------------------------------------------------------------------------------
1 | from schemata.teletype.v300 import TeletypePresetSchema_v300
2 |
3 | TELETYPE_SCHEMATA = {
4 | '3.0.0': TeletypePresetSchema_v300,
5 | }
6 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/teletype/teletype_preset_schema.py:
--------------------------------------------------------------------------------
1 | from preset_schema import PresetSchema
2 |
3 |
4 | class TeletypePresetSchema(PresetSchema):
5 | def firmware_name(self):
6 | return 'teletype'
7 |
8 | def check(self, nvram_data):
9 | if nvram_data.fresh != 0x22:
10 | print("this firmware image hasn't ever been run (or is corrupt)")
11 | return False
12 | return True
13 |
14 | def root_type(self):
15 | return 'nvram_data_t'
16 |
17 | def address(self):
18 | return 0x80040000
19 |
--------------------------------------------------------------------------------
/tools/flash_tools/schemata/teletype/v300.py:
--------------------------------------------------------------------------------
1 | from schemata.teletype.teletype_preset_schema import TeletypePresetSchema
2 |
3 |
4 | class TeletypePresetSchema_v300(TeletypePresetSchema):
5 | def app_list(self):
6 | return ['tt']
7 |
8 | def meta(self, nvram):
9 | return {}
10 |
11 | def shared(self, nvram):
12 | return {}
13 |
14 | def cdef(self):
15 | return r'''
16 | typedef enum {
17 | M_LIVE,
18 | M_EDIT,
19 | M_PATTERN,
20 | M_PRESET_W,
21 | M_PRESET_R,
22 | M_HELP
23 | } tele_mode_t;
24 |
25 | typedef enum { NUMBER, OP, MOD, PRE_SEP, SUB_SEP } tele_word_t;
26 |
27 | #define FIRSTRUN_KEY 0x22
28 | #define BUTTON_STATE_SIZE 32
29 | #define GRID_FADER_COUNT 64
30 | #define PATTERN_COUNT 4
31 | #define PATTERN_LENGTH 64
32 | #define COMMAND_MAX_LENGTH 16
33 | #define SCRIPT_MAX_COMMANDS 6
34 | #define SCRIPT_COUNT 11
35 | #define SCENE_TEXT_LINES 32
36 | #define SCENE_TEXT_CHARS 32
37 | #define SCENE_SLOTS 32
38 |
39 | typedef int16_t SCALE_T;
40 | typedef int32_t _SCALE_T;
41 |
42 | typedef struct {
43 | SCALE_T p_min;
44 | SCALE_T p_max;
45 | SCALE_T i_min;
46 | SCALE_T i_max;
47 | } cal_data_t;
48 |
49 |
50 | typedef struct {
51 | uint8_t tag; // tele_word_t
52 | int16_t value;
53 | } tele_data_t;
54 |
55 | typedef struct {
56 | uint8_t length;
57 | int8_t separator;
58 | tele_data_t data[COMMAND_MAX_LENGTH];
59 | bool comment; // bool
60 | } tele_command_t;
61 |
62 | typedef struct {
63 | int16_t count;
64 | int16_t mod;
65 | uint8_t skip;
66 | } every_count_t;
67 |
68 | typedef struct {
69 | int16_t idx;
70 | uint16_t len;
71 | uint16_t wrap;
72 | int16_t start;
73 | int16_t end;
74 | int16_t val[PATTERN_LENGTH];
75 | } scene_pattern_t;
76 |
77 | typedef struct {
78 | uint8_t l;
79 | tele_command_t c[SCRIPT_MAX_COMMANDS];
80 | every_count_t every[SCRIPT_MAX_COMMANDS];
81 | uint32_t last_time;
82 | } scene_script_t;
83 |
84 | typedef struct {
85 | uint8_t button_states[BUTTON_STATE_SIZE];
86 | uint8_t fader_states[GRID_FADER_COUNT];
87 | } grid_data_t;
88 |
89 | // NVRAM data structure located in the flash array.
90 | typedef const struct {
91 | scene_script_t scripts[SCRIPT_COUNT - 1]; // Exclude TEMP script
92 | scene_pattern_t patterns[PATTERN_COUNT];
93 | grid_data_t grid_data;
94 | char text[SCENE_TEXT_LINES][SCENE_TEXT_CHARS];
95 | } nvram_scene_t;
96 |
97 | typedef const struct {
98 | nvram_scene_t scenes[SCENE_SLOTS];
99 | uint8_t last_scene;
100 | uint8_t last_mode; // tele_mode_t
101 | uint8_t fresh;
102 | cal_data_t cal;
103 | } nvram_data_t;
104 | '''
105 |
--------------------------------------------------------------------------------