├── .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 | [![Build Status](https://travis-ci.org/monome/ansible.svg?branch=master)](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 | --------------------------------------------------------------------------------