--- /dev/null
+*.o
+*.lst
+*.hex
+*.mot
+*.x
+*.map
+img2fnt
+font.h
+sinus
+sinus.h
+memory.ld
+size.tmp
--- /dev/null
+"reset_program.o" "interrupt_handlers.o" "vector_table.o" "aix.o" "main.o" "lcd.o" "gui.o" "wave.o" "ctrl.o" "fs.o" "debug.o"
\ No newline at end of file
--- /dev/null
+/* ANALOG INPUT EXPANDER */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "klavirko-ui.h"
+#include "aix.h"
+#include "debug.h"
+#include "wave.h"
+#include "gui.h"
+
+ uint16_t aix_data[N_AIX_DATA] = AIX_DATA_INIT;
+volatile uint8_t aix_buffer[N_AIX_BUFFER];
+volatile uint8_t aix_buffer_r = 0;
+volatile uint8_t aix_buffer_w = 0;
+ uint8_t aix_check; // frame checksum
+ uint8_t aix_i = 0; // frame byte index
+ uint8_t aix_sel = 0; // setting index
+ uint8_t aix_sw_old = 0; // old switch state
+ uint8_t aix_sw_new = 0; // new switch state
+ uint8_t aix_sw_count = 0;// switch state debouncer
+ uint16_t aix_val = 0; // setting value
+volatile uint16_t aix_timeout = 0; // timeout for no AIX communication
+
+
+inline void aix_watchdog (void) // monitor if AIX communication still working
+{
+ if (aix_timeout < AIX_TIMEOUT)
+ {
+ ++aix_timeout;
+ if(aix_timeout == AIX_TIMEOUT)
+ {
+ debug_string("AIX TIMEOUT!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_AIX);
+ }
+ }
+}
+
+inline void int_aix_rx (void) // received byte from AIX
+{
+ uint8_t data;
+
+ data = AIX_RX__SDR; // get byte
+
+ if((aix_buffer_w + 1 == aix_buffer_r) || (aix_buffer_w + 1 == aix_buffer_r + N_AIX_BUFFER)) // buffer overflow
+ {}
+ else
+ {
+ aix_buffer[aix_buffer_w] = data;
+ // advance the pointer
+ if (aix_buffer_w >= N_AIX_BUFFER - 1)
+ aix_buffer_w = 0;
+ else
+ ++aix_buffer_w;
+ }
+}
+
+inline void int_aix_err (void) // received error from AIX
+{
+ volatile uint8_t data; //just to make sure a read is performed
+ uint16_t err;
+
+ // not interested which error occurred and why
+ // just clear and continue
+ // frames have checksums anyway
+
+ data = AIX_RX__SDR;
+ err = AIX_RX__SSR;
+ AIX_RX__SIR = err;
+}
+
+inline void setup_aix (void)
+{
+ PER0 |= 0b00000100; //enable serial array unit 0
+
+ SPS0 = (SPS0 & 0xfff0) | 0x0001; //CK00 = fclk/2 = 16MHz
+
+ AIX_TX__SMR = 0b0000000000100011; //CK00, int. on buf empty
+ AIX_RX__SMR = 0b0000000100100010; //CK00, ...
+
+ AIX_TX__SCR = 0b1000000010010111; //8n1, LSB
+ AIX_RX__SCR = 0b0100010010010111;
+
+ AIX_TX__SDR = 0x8c00l; //16MHz / 138 = 115942.029bps
+ AIX_RX__SDR = 0x8c00l;
+
+ SOL0 &= ~0x0001;
+ SO0 |= 0b0000001100000011;
+
+ AIX_TX__SOE = 1;
+
+ AIX_TX__PM = 0;
+ AIX_TX__POM = 0;
+ AIX_TX__PU = 0;
+ AIX_TX = 1;
+
+ AIX_RX__POM = 0;
+ AIX_RX__PIM = 0;
+ AIX_RX__PM = 1;
+ AIX_RX__PU = 0;
+ AIX_RX = 1;
+
+ AIX_TX__SS = 1;
+ AIX_RX__SS = 1;
+
+ AIX_RX__MK = 0;
+ AIX_RX__MKE = 0;
+}
+
+void handle_aix (void)
+{
+ uint8_t data;
+ int16_t diff;
+
+ if (aix_buffer_r != aix_buffer_w) // data waiting in buffer
+ {
+ // get data; advance pointer
+ data = aix_buffer[aix_buffer_r];
+ if(aix_buffer_r >= N_AIX_BUFFER - 1)
+ aix_buffer_r = 0;
+ else
+ ++aix_buffer_r;
+
+ if (data == '\n') //end of frame
+ {
+ if( //frame is valid:
+ aix_check == 0 && // correct checksum
+ aix_i != 0 && // frame not empty
+ (((1<<aix_sel) & AIX_UNUSED)==0) && // not for an unused setting
+ aix_val <= AIX_DATA_MAX // value in range
+ ){
+ aix_timeout = 0; // clear the 'watchdog'
+
+ // has value changed enough?
+ diff = (int16_t)(aix_val - aix_data[aix_sel]);
+ if ((diff >= AIX_MIN_DIFF) || (diff <= 0 - AIX_MIN_DIFF))
+ {
+ if (aix_data[aix_sel] == AIX_DATA_DEFAULT) // first read ever
+ aix_data[aix_sel] = aix_val;
+ else
+ aix_data[aix_sel] = (aix_val + aix_data[aix_sel])>>1; // low pass approach
+
+
+ if((1<<aix_sel)&AIX_ADSR) // envelope to change
+ update_adsr();
+ else if((1<<aix_sel)&AIX_WAVE) //waveform to change
+ update_wave();
+ else if(aix_sel == AIX_CONTRAST) // contrast to change
+ lcd_contrast(aix_val);
+ else if(aix_sel == AIX_BRIGHTNESS) // brightness to change
+ lcd_brightness(aix_val);
+ }
+ // debounce the waveform selector switch
+ if (aix_sw_new != aix_sw_old)
+ aix_sw_count = 0;
+ else if (aix_sw_count < AIX_SW_DEBOUNCE)
+ {
+ ++aix_sw_count;
+ if (aix_sw_count == AIX_SW_DEBOUNCE)
+ {
+ if (aix_sw_new != aix_data[AIX_SW])
+ {
+ // debounce completed, update the waveform
+ aix_data[AIX_SW] = aix_sw_new;
+ update_wave();
+ }
+ }
+ }
+ aix_sw_old = aix_sw_new;
+ }
+ // reset state
+ aix_i = 0;
+ aix_check = 0;
+ }
+ else
+ {
+ if (data >= '0' && data <= '9')
+ data -= '0';
+ else if (data >= 'A' && data <= 'F')
+ data -= 'A' - 10;
+ else if (data >= 'a' && data <= 'f')
+ data -= 'a' - 10;
+ else if (data >= 'G' && data <= 'V')
+ data -= 'G';
+ else if (data >= 'g' && data <= 'v')
+ data -= 'g';
+ else
+ data = 0;
+
+ if (aix_i & 0x1) // high half byte
+ data <<= 4;
+
+ aix_check += data; // update checksum
+
+ switch (aix_i) // which byte?
+ {
+ case 0: // setting index / command ID
+ aix_sel = data;
+ break;
+ case 1: // value bits 7-4
+ aix_val = 0;
+ case 2: // value bits 3-0
+ aix_val |= data;
+ break;
+ case 3: // switch state
+ aix_sw_new = data;
+ break;
+ case 4: // value bits 9-8
+ *(((uint8_t*)&aix_val)+1) |= data;
+ break;
+ default:
+ break;
+ }
+
+ ++aix_i; // next byte
+ }
+ }
+}
+
+void debug_aix (const uint8_t blocking) // print AIX state
+{
+ debug_string("AIX: ", blocking);
+ debug_hex(aix_data[AIX_BRIGHTNESS], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_CONTRAST], blocking, 3, 1);
+ debug_string(" | ",blocking);
+ debug_hex(aix_data[AIX_A], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_D], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_S], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_R], blocking, 3, 1);
+ debug_string(" | ",blocking);
+ debug_hex(aix_data[AIX_V1], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_V2], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_V3], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_V4], blocking, 3, 1);
+ debug_string(" | ",blocking);
+ debug_hex(aix_data[AIX_T1], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_T2], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_T3], blocking, 3, 1);
+ debug_byte(' ',blocking);
+ debug_hex(aix_data[AIX_T4], blocking, 3, 1);
+ debug_string(" | ",blocking);
+ debug_hex(aix_data[AIX_SW], blocking, 3, 1);
+ debug_string("\r\n",blocking);
+}
--- /dev/null
+/* ANALOG INPUT EXPANDER */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+
+/*
+UI layout:
+
+ F
+ T 0 |o######| E D | C B A 9
+ V 1 2 | 3 4 5 6
+
+*/
+
+// index' of all settings
+
+#define AIX_BRIGHTNESS 0xF
+#define AIX_CONTRAST 0x0
+
+#define AIX_A 0xE
+#define AIX_D 0xD
+#define AIX_S 0x1
+#define AIX_R 0x2
+
+#define AIX_V1 0xC
+#define AIX_V2 0xB
+#define AIX_V3 0xA
+#define AIX_V4 0x9
+
+#define AIX_T1 0x3
+#define AIX_T2 0x4
+#define AIX_T3 0x5
+#define AIX_T4 0x6
+
+#define AIX_UNUSED1 0x07
+#define AIX_UNUSED2 0x08
+
+#define AIX_UNUSED (\
+ (1 << AIX_UNUSED1)|\
+ (1 << AIX_UNUSED2)\
+)
+
+#define AIX_SW 0x10
+
+#define AIX_ADSR (\
+ (1 << AIX_A)|\
+ (1 << AIX_D)|\
+ (1 << AIX_S)|\
+ (1 << AIX_R)\
+)
+#define AIX_WAVE (\
+ (1 << AIX_V1)|\
+ (1 << AIX_V2)|\
+ (1 << AIX_V3)|\
+ (1 << AIX_V4)|\
+ (1 << AIX_T1)|\
+ (1 << AIX_T2)|\
+ (1 << AIX_T3)|\
+ (1 << AIX_T4)\
+)
+
+#define N_AIX_DATA 17
+#define AIX_DATA_DEFAULT 0x0fff
+#define AIX_DATA_MAX 0x03ff
+#define AIX_DATA_INIT \
+{ \
+ AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, \
+ AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, \
+ AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, \
+ AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, AIX_DATA_DEFAULT, \
+ AIX_DATA_DEFAULT \
+}
+#define N_AIX_BUFFER 10
+#define AIX_MIN_DIFF 8
+#define AIX_TIMEOUT 1190
+#define AIX_SW_DEBOUNCE 60
+
+inline void aix_watchdog(void) LOWTEXT; // monitor if AIX communication still working
+inline void int_aix_rx (void) LOWTEXT_INT; // received byte from AIX
+inline void int_aix_err(void) LOWTEXT_INT; // received error from AIX
+inline void setup_aix(void);
+ void handle_aix(void);
+ void debug_aix (const uint8_t blocking); // print AIX state
+
+extern uint16_t aix_data[N_AIX_DATA];
--- /dev/null
+/* COMMUNICATING WITH MAIN CONTROLLER */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include "klavirko-ui.h"
+#include "ctrl.h"
+#include "wave.h"
+#include "debug.h"
+#include "gui.h"
+
+ uint8_t ctrl_databuffer[N_CTRL_DATABUFFER];
+volatile uint8_t ctrl_rxbuffer[N_CTRL_RXBUFFER];
+volatile uint8_t ctrl_rxbuffer_r = 0;
+volatile uint8_t ctrl_rxbuffer_w = 0;
+ uint8_t ctrl_txbuffer[N_CTRL_TXBUFFER];
+ uint8_t ctrl_txbuffer_r = 0;
+ uint8_t ctrl_txbuffer_w = 0;
+volatile uint8_t ctrl_error = 0;
+
+ uint8_t ctrl_state = CTRL_WAIT;
+ uint8_t ctrl_retry = 0;
+volatile uint16_t ctrl_timeout = 0;
+
+ uint16_t ctrl_request = 0;
+ uint16_t ctrl_finished = 0;
+ uint16_t ctrl_failed = 0;
+ uint16_t ctrl_action = 0;
+ uint8_t ctrl_cmd = CMD_NOP;
+ uint8_t ctrl_resp = 0;
+ uint8_t ctrl_checksum = 0;
+ uint8_t ctrl_halfbyte = 0;
+ int16_t ctrl_index = 0;
+ int16_t ctrl_limit = 0;
+
+ uint8_t midi_id = 0;
+ uint8_t midi_id_out = 16;
+ uint8_t midi_pedal_en = 1;
+
+
+inline void ctrl_watchdog(void)
+{
+ ++ctrl_timeout;
+}
+
+inline void int_ctrl_rx(void) // received byte from CTRL
+{
+ uint8_t data;
+
+ data = CTRL_RX__SDR; // get byte
+
+ if((ctrl_rxbuffer_w + 1 == ctrl_rxbuffer_r) || (ctrl_rxbuffer_w + 1 == ctrl_rxbuffer_r + N_CTRL_RXBUFFER)) // buffer overflow
+ ctrl_error |= ERR_OVERFLOW;
+ else
+ {
+ ctrl_rxbuffer[ctrl_rxbuffer_w] = data;
+ // advance the pointer
+ if (ctrl_rxbuffer_w >= N_CTRL_RXBUFFER - 1)
+ ctrl_rxbuffer_w = 0;
+ else
+ ++ctrl_rxbuffer_w;
+ }
+}
+
+inline void int_ctrl_err(void) // received error from CTRL
+{
+ volatile uint8_t data; //just to make sure a read is performed
+ uint16_t err;
+
+ // not interested which error occurred and why
+ // just clear and continue
+ // frames have checksums anyway
+
+ data = CTRL_RX__SDR;
+ err = CTRL_RX__SSR;
+ CTRL_RX__SIR = err;
+
+ ctrl_error |= ERR_UART;
+}
+
+inline void setup_ctrl (void)
+{
+ PER0 |= 0b00000100; //enable serial array unit 0
+
+ SPS0 = (SPS0 & 0xff0f) | 0x0010; //CK01 = fclk/2 = 16MHz
+
+ CTRL_TX__SMR = 0b1000000000100011; //CK01, int. on buf empty
+ CTRL_RX__SMR = 0b1000000100100010; //CK01, ...
+
+ CTRL_TX__SCR = 0b1000000010010111; //8n1, LSB
+ CTRL_RX__SCR = 0b0100010010010111;
+
+ CTRL_TX__SDR = 0x8c00l; //16MHz / 138 = 115942.029bps
+ CTRL_RX__SDR = 0x8c00l;
+
+ SOL0 &= ~0x0004; //nonreversed
+ SO0 |= 0b0000110000001100;
+
+ CTRL_TX__SOE = 1;
+
+ CTRL_TX__POM = 0;
+ CTRL_TX__PMC = 0;
+ CTRL_TX__PM = 0;
+ CTRL_TX__PU = 0;
+ CTRL_TX = 1;
+
+ CTRL_RX__POM = 0;
+ CTRL_RX__PIM = 0;
+ CTRL_RX__PMC = 0;
+ CTRL_RX__PM = 1;
+ CTRL_RX__PU = 0;
+ CTRL_RX = 1;
+
+ CTRL_TX__SS = 1;
+ CTRL_RX__SS = 1;
+
+ CTRL_RX__MK = 0;
+ CTRL_RX__MKE = 0;
+}
+
+inline void init_ctrl (void)
+{
+ ctrl_request |= FLAGS_INIT_CTRL;
+
+ while (
+ ((ctrl_finished & FLAGS_INIT_CTRL) != FLAGS_INIT_CTRL) && // still unfinished requests
+ (ctrl_failed == 0) // none of them failed
+ ){
+ handle_ctrl();
+ handle_debug();
+ }
+}
+
+void handle_ctrl (void)
+{
+ uint8_t io;
+ // no 'else's to allow fall throughs
+
+ if (ctrl_state == CTRL_WAIT && ctrl_request != 0) // new request to handle
+ {
+ // check which request
+ if(ctrl_request & FLAG_GET_TIMING)
+ {
+ ctrl_action = FLAG_GET_TIMING;
+ ctrl_cmd = CMD_GET_TIMING;
+ }
+ else if(ctrl_request & FLAG_GET_MAX_TUNING)
+ {
+ ctrl_action = FLAG_GET_MAX_TUNING;
+ ctrl_cmd = CMD_GET_MAX_TUNING;
+ }
+ else if(ctrl_request & FLAG_SET_TUNING)
+ {
+ ctrl_action = FLAG_SET_TUNING;
+ ctrl_cmd = CMD_SET_TUNING;
+ }
+ else if(ctrl_request & FLAG_SET_ADSR)
+ {
+ ctrl_action = FLAG_SET_ADSR;
+ ctrl_cmd = CMD_SET_ADSR;
+ }
+ else if(ctrl_request & FLAG_SET_SAMPLE)
+ {
+ ctrl_action = FLAG_SET_SAMPLE;
+ ctrl_cmd = CMD_SET_SAMPLE;
+ }
+ else if(ctrl_request & FLAG_GET_MIDI_CFG)
+ {
+ ctrl_action = FLAG_GET_MIDI_CFG;
+ ctrl_cmd = CMD_GET_MIDI_CFG;
+ }
+ else if(ctrl_request & FLAG_SET_MIDI_CFG)
+ {
+ ctrl_action = FLAG_SET_MIDI_CFG;
+ ctrl_cmd = CMD_SET_MIDI_CFG;
+ }
+ else // sorry, invalid
+ {
+ ctrl_action = 0;
+ ctrl_cmd = CMD_NOP;
+ }
+
+ if (ctrl_action) // OK, stuff to do
+ {
+ ctrl_state = CTRL_PRE_EXEC;
+ ctrl_retry = 0;
+ ctrl_error = 0;
+ ctrl_request &= ~ctrl_action;
+ ctrl_finished &= ~ctrl_action;
+ ctrl_failed &= ~ctrl_action;
+ }
+ else // back to waiting
+ {
+ ctrl_state = CTRL_WAIT;
+ ctrl_request = 0;
+ }
+ }
+
+ if (ctrl_state == CTRL_PRE_EXEC) // execute action before sending command
+ {
+ ctrl_error = 0;
+ switch(ctrl_cmd)
+ {
+ case CMD_SET_SAMPLE:
+ memcpy(ctrl_databuffer, sample, N_SAMPLE);
+ ctrl_limit = N_SAMPLE;
+ break;
+ case CMD_SET_ADSR:
+ *((uint32_t*)ctrl_databuffer) = adsr_A;
+ *((uint32_t*)(ctrl_databuffer+4)) = adsr_D;
+ *((uint32_t*)(ctrl_databuffer+8)) = adsr_S;
+ *((uint32_t*)(ctrl_databuffer+12)) = adsr_R;
+ ctrl_limit = 4*4;
+ break;
+ case CMD_SET_TUNING:
+ *((uint16_t*)ctrl_databuffer) = tuning;
+ *((int8_t*)(ctrl_databuffer+2)) = transp;
+ ctrl_limit = 3;
+ break;
+ case CMD_SET_MIDI_CFG:
+ ctrl_databuffer[0] = midi_id;
+ ctrl_databuffer[1] = midi_id_out;
+ ctrl_databuffer[2] = midi_pedal_en;
+ ctrl_limit = 3;
+ break;
+ default:
+ ctrl_limit = 0;
+ break;
+ }
+ ctrl_state = CTRL_SEND;
+ ctrl_checksum = 0;
+ ctrl_index = -1;
+ }
+
+ while (ctrl_state == CTRL_SEND) // send the command
+ {
+ if((ctrl_txbuffer_w + 1 == ctrl_txbuffer_r) || (ctrl_txbuffer_w + 1 == ctrl_txbuffer_r + N_CTRL_TXBUFFER)) // no place in buffer
+ break;
+
+ if (ctrl_index < 0) // start of frame, command id
+ {
+ io = ctrl_cmd;
+ ctrl_checksum -= ctrl_cmd;
+ ctrl_index = 0;
+ ctrl_halfbyte = 0;
+ }
+ else if (ctrl_index > ctrl_limit) // end of frame
+ {
+ io = '\n';
+ ctrl_state = CTRL_SWITCH; // GOTO next state
+ ctrl_rxbuffer_r = ctrl_rxbuffer_w;
+ }
+ else // data byte
+ {
+ if (ctrl_index == ctrl_limit) // last byte, the checksum
+ io = ctrl_checksum;
+ else
+ io = ctrl_databuffer[ctrl_index];
+ if (ctrl_halfbyte == 0)
+ {
+ io >>= 4;
+ ctrl_halfbyte = 1;
+ }
+ else
+ {
+ ctrl_checksum -= io;
+ io &= 0x0f;
+ ctrl_halfbyte = 0;
+ ++ctrl_index;
+ }
+ if (io > 9)
+ io += ('a' - 10);
+ else
+ io += '0';
+ }
+
+ // put to buffer, adnvance the pointer
+ ctrl_txbuffer[ctrl_txbuffer_w] = io;
+ if (ctrl_txbuffer_w >= N_CTRL_TXBUFFER - 1)
+ ctrl_txbuffer_w = 0;
+ else
+ ++ctrl_txbuffer_w;
+ }
+
+ if (ctrl_txbuffer_r != ctrl_txbuffer_w) // data in output buffer
+ {
+ if(!(CTRL_TX__SSR & 0b01000000)) // uart is ready
+ {
+ CTRL_TX__IF = 0;
+ CTRL_TX__SDR = ctrl_txbuffer[ctrl_txbuffer_r]; // send the byte
+
+ // advance the pointer
+ if (ctrl_txbuffer_r >= N_CTRL_RXBUFFER - 1)
+ ctrl_txbuffer_r = 0;
+ else
+ ++ctrl_txbuffer_r;
+ }
+ }
+
+ if (ctrl_state == CTRL_SWITCH) // switch from send to receive; recalculate frame length
+ {
+ ctrl_index = 0;
+ ctrl_halfbyte = 0;
+ ctrl_timeout = 0;
+ // ctrl_error = 0;
+
+ switch(ctrl_cmd)
+ {
+ case CMD_GET_MAX_TUNING:
+ ctrl_limit = 2;
+ break;
+ case CMD_GET_TIMING:
+ ctrl_limit = 2 * 4;
+ break;
+ case CMD_GET_MIDI_CFG:
+ ctrl_limit = 3;
+ break;
+ default:
+ ctrl_limit = 0;
+ break;
+ }
+
+ ctrl_state = CTRL_RECEIVE;
+ ctrl_resp = CMD_NOP;
+ }
+
+ while (ctrl_rxbuffer_r != ctrl_rxbuffer_w) // data in input buffer
+ {
+ // get the byte, advance the pointer
+ io = ctrl_rxbuffer[ctrl_rxbuffer_r];
+ if(ctrl_rxbuffer_r >= N_CTRL_RXBUFFER -1 )
+ ctrl_rxbuffer_r = 0;
+ else
+ ++ctrl_rxbuffer_r;
+
+ if (io == CMD_ERR) // received a complain from CTRL
+ {
+ // drop any action, immediately switch to listen
+ ctrl_state = CTRL_RECEIVE;
+ ctrl_txbuffer_r = ctrl_txbuffer_w;
+ }
+
+ if (ctrl_state == CTRL_RECEIVE) // actually expecting to receive
+ {
+ if (io == '\n') // end of frame
+ {
+ if (ctrl_cmd != CMD_NOP)
+ {
+ if (ctrl_resp != ctrl_cmd) // response to the same id?
+ ctrl_error |= ERR_MISMATCH;
+ if (ctrl_checksum != 0) // checksum correct?
+ ctrl_error |= ERR_CHECKSUM;
+ if (ctrl_index != ctrl_limit + 1) // length correct?
+ ctrl_error |= ERR_LENGTH;
+ ctrl_state = CTRL_POST_EXEC; // GOTO next state
+ }
+ }
+ else if (io <= ' ') // whitespace to ignore
+ {
+
+ }
+ else if ( // data
+ (io >= '0' && io <= '9')||
+ (io >= 'A' && io <= 'F')||
+ (io >= 'a' && io <= 'f')
+ ){
+ if (ctrl_index <= ctrl_limit)
+ {
+ if (io >= 'a')
+ io -= ('a'-10);
+ else if (io >= 'A')
+ io -= ('A'-10);
+ else
+ io -= '0';
+
+ if (ctrl_halfbyte)
+ {
+ ctrl_checksum += io;
+ if (ctrl_index < ctrl_limit)
+ ctrl_databuffer[ctrl_index] |= io;
+ ++ctrl_index;
+ ctrl_halfbyte = 0;
+ }
+ else
+ {
+ io <<= 4;
+ ctrl_checksum += io;
+ if (ctrl_index < ctrl_limit)
+ ctrl_databuffer[ctrl_index] = io;
+ ctrl_halfbyte = 1;
+ }
+ }
+ else
+ ctrl_index = ctrl_limit + 2;
+ }
+ else //response index
+ {
+ ctrl_resp = io;
+ ctrl_checksum = io;
+ ctrl_index = 0;
+ ctrl_halfbyte = 0;
+
+ }
+ }
+ }
+
+ if (ctrl_state == CTRL_RECEIVE) // still expecting to receive
+ {
+ if (ctrl_timeout >= CTRL_TIMEOUT)
+ ctrl_error |= ERR_TIMEOUT;
+ if (ctrl_error != 0)
+ ctrl_state = CTRL_POST_EXEC;
+ }
+
+ if (ctrl_state == CTRL_POST_EXEC) // execute action after receiving response
+ {
+ if (ctrl_error != 0) // there was error, handle this instead
+ {
+ debug_string("CTRL_ERR: ", 1);
+ debug_hex(ctrl_error, 0, 2, 1);
+ debug_string(" !\r\n", 1);
+
+ ++ctrl_retry;
+ if(ctrl_retry >= CTRL_RETRY)
+ {
+ debug_string("CTRL_TIMEOUT!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_CTRL);
+ ctrl_failed |= ctrl_action;
+ ctrl_state = CTRL_WAIT; // give up
+ }
+ else
+ {
+ ctrl_state = CTRL_PRE_EXEC; // try again
+ }
+ }
+ else
+ {
+ switch (ctrl_cmd)
+ {
+ case CMD_GET_TIMING:
+ set_timing(
+ *((uint32_t*)ctrl_databuffer),
+ *((uint32_t*)(ctrl_databuffer+4))
+ );
+ break;
+ case CMD_GET_MAX_TUNING:
+ set_max_tuning (*((uint16_t*)ctrl_databuffer));
+ break;
+ case CMD_GET_MIDI_CFG:
+ midi_id = (ctrl_databuffer[0]<N_MIDI_ID) ? ctrl_databuffer[0] : N_MIDI_ID;
+ midi_id_out = ctrl_databuffer[1] & MIDI_ID_MASK;
+ midi_pedal_en = ctrl_databuffer[2];
+ ctrl_finished |= FLAG_GET_MIDI_CFG;
+ break;
+ case CMD_SET_TUNING:
+ case CMD_SET_ADSR:
+ case CMD_SET_SAMPLE:
+ case CMD_SET_MIDI_CFG:
+ break;
+ default:
+ ctrl_action = 0;
+ break;
+ }
+ ctrl_finished |= ctrl_action;
+ ctrl_state = CTRL_WAIT; // done; wait for next
+ ctrl_retry = 0;
+ }
+ }
+}
+
+//mark changed data to be (re)sent to CTRL
+
+inline void ctrl_update_wave (void)
+{
+ ctrl_request |= FLAG_SET_SAMPLE;
+}
+
+inline void ctrl_update_adsr (void)
+{
+ ctrl_request |= FLAG_SET_ADSR;
+}
+
+inline void ctrl_update_tuning (void)
+{
+ ctrl_request |= FLAG_SET_TUNING;
+}
+
+inline void ctrl_update_midi (void)
+{
+ ctrl_request |= FLAG_SET_MIDI_CFG;
+}
--- /dev/null
+/* COMMUNICATING WITH MAIN CONTROLLER */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+
+// commands
+#define CMD_NOP 0
+#define CMD_ERR '!'
+#define CMD_GET_SAMPLE 'G'
+#define CMD_SET_SAMPLE 'g'
+#define CMD_GET_SAMPLE_BYTE 'H'
+#define CMD_SET_SAMPLE_BYTE 'h'
+#define CMD_GET_ADSR 'I'
+#define CMD_SET_ADSR 'i'
+#define CMD_GET_TUNING 'J'
+#define CMD_SET_TUNING 'j'
+#define CMD_GET_MAX_TUNING 'K'
+#define CMD_GET_TIMING 'L'
+#define CMD_GET_MIDI_CFG 'M'
+#define CMD_SET_MIDI_CFG 'm'
+
+// request/status flags
+#define FLAG_ERR 0x0001
+#define FLAG_GET_SAMPLE 0x0002
+#define FLAG_SET_SAMPLE 0x0004
+#define FLAG_GET_SAMPLE_BYTE 0x0008
+#define FLAG_SET_SAMPLE_BYTE 0x0010
+#define FLAG_GET_ADSR 0x0020
+#define FLAG_SET_ADSR 0x0040
+#define FLAG_GET_TUNING 0x0080
+#define FLAG_SET_TUNING 0x0100
+#define FLAG_GET_MAX_TUNING 0x0200
+#define FLAG_GET_TIMING 0x0400
+#define FLAG_GET_MIDI_CFG 0x0800
+#define FLAG_SET_MIDI_CFG 0x1000
+
+// which actions to request at start
+#define FLAGS_INIT_CTRL ( \
+ FLAG_GET_TIMING | \
+ FLAG_GET_MAX_TUNING | \
+ FLAG_GET_MIDI_CFG | \
+ FLAG_SET_TUNING \
+)
+
+// state machine
+
+#define CTRL_WAIT 0
+#define CTRL_PRE_EXEC 1
+#define CTRL_SEND 2
+#define CTRL_SWITCH 3
+#define CTRL_RECEIVE 4
+#define CTRL_POST_EXEC 5
+
+// error flags
+
+#define ERR_NO 0x00
+#define ERR_UART 0x01
+#define ERR_OVERFLOW 0x02
+#define ERR_CHECKSUM 0x04
+#define ERR_LENGTH 0x08
+#define ERR_MISMATCH 0x10
+#define ERR_TIMEOUT 0x20
+
+#define CTRL_TIMEOUT 110
+#define CTRL_RETRY 64
+
+#define N_CTRL_DATABUFFER 256 //at least as big as sample
+#define N_CTRL_RXBUFFER 32
+#define N_CTRL_TXBUFFER 32
+
+#define N_MIDI_ID 16
+#define MIDI_ID_MASK 0x0f
+
+extern uint8_t midi_id;
+extern uint8_t midi_id_out;
+extern uint8_t midi_pedal_en;
+
+inline void ctrl_watchdog (void) LOWTEXT;
+inline void int_ctrl_rx (void) LOWTEXT_INT; // received byte from CTR
+inline void int_ctrl_err (void) LOWTEXT_INT; // received error from CTR
+inline void setup_ctrl (void);
+inline void init_ctrl (void);
+ void handle_ctrl (void);
+//mark changed data to be (re)sent to CTRL
+inline void ctrl_update_wave (void);
+inline void ctrl_update_adsr (void);
+inline void ctrl_update_tuning (void);
+inline void ctrl_update_midi (void);
--- /dev/null
+/* DEBUG SERIAL OUTPUT */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "klavirko-ui.h"
+#include "debug.h"
+#include "main.h"
+
+uint8_t debug_buffer[N_DEBUG_BUFFER];
+uint8_t debug_buffer_r = 0;
+uint8_t debug_buffer_w = 0;
+
+//using AIX TX as debug output now
+void handle_debug(void)
+{
+ uint8_t byte;
+
+ if(debug_buffer_r != debug_buffer_w) // data waiting in buffer
+ {
+ byte = debug_buffer[debug_buffer_r]; // get the byte
+
+ if(!(AIX_TX__SSR & 0b01000000)) // uart is ready
+ {
+ AIX_TX__IF = 0;
+ AIX_TX__SDR = byte;
+ }
+ else
+ return;
+ // advance the pointer
+ if(debug_buffer_r >= N_DEBUG_BUFFER - 1)
+ debug_buffer_r = 0;
+ else
+ ++debug_buffer_r;
+ }
+}
+
+void debug_byte ( // send a byte to debug output
+ const uint8_t value,
+ const uint8_t blocking
+)
+{
+ while((debug_buffer_w + 1 == debug_buffer_r) || (debug_buffer_w + 1 == debug_buffer_r + N_DEBUG_BUFFER))
+ {
+ if (blocking)
+ handle_debug();
+ else
+ return;
+ }
+ debug_buffer[debug_buffer_w] = value;
+ if(debug_buffer_w >= N_DEBUG_BUFFER - 1)
+ debug_buffer_w = 0;
+ else
+ ++debug_buffer_w;
+}
+
+void debug_string ( // send a string to debug output
+ const uint8_t * const text,
+ const uint8_t blocking
+)
+{
+ uint16_t i;
+ for(i=0; text[i] != '\0'; ++i)
+ debug_byte(text[i], blocking);
+}
+
+// todo: use make_dec/hex_string() to avoid code duplication ?
+
+void debug_hex ( // send hexadecimal number to debug output
+ const uint32_t value,
+ const uint8_t blocking,
+ const uint16_t min_digits,
+ const uint8_t uppercase
+)
+{
+ uint8_t x;
+ uint8_t text[9];
+
+ x = make_hex_string(
+ text,
+ value,
+ min_digits,
+ 8,
+ uppercase
+ );
+ text[x] = '\0';
+ debug_string(text, blocking);
+}
+
+void debug_dec ( // send decimal number to debug output
+ const uint32_t value,
+ const uint8_t blocking,
+ const uint16_t min_digits
+)
+{
+ uint8_t text[11];
+ uint8_t x;
+
+ x = make_dec_string(
+ text,
+ value,
+ min_digits,
+ 10
+ );
+ text[x] = '\0';
+ debug_string(text, blocking);
+}
--- /dev/null
+/* DEBUG SERIAL OUTPUT */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+
+//using TX of AIX as debug output
+
+#define N_DEBUG_BUFFER 256
+
+void handle_debug(void);
+void debug_byte ( // send a byte to debug output
+ const uint8_t value,
+ const uint8_t blocking
+);
+void debug_string ( // send a string to debug output
+ const uint8_t * const text,
+ const uint8_t blocking
+);
+void debug_hex ( // send hexadecimal number to debug output
+ const uint32_t value,
+ const uint8_t blocking,
+ const uint16_t min_digits,
+ const uint8_t uppercase
+);
+void debug_dec ( // send decimal number to debug output
+ const uint32_t value,
+ const uint8_t blocking,
+ const uint16_t min_digits
+);
--- /dev/null
+/* STORAGE OF SETTINGS */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include "klavirko-ui.h"
+#include "fs.h"
+#include "debug.h"
+#include "main.h"
+#include "gui.h"
+#include "wave.h"
+
+int16_t fs_index0 = -1;
+int16_t fs_index1 = -1;
+int16_t fs_newindex0 = -1;
+int16_t fs_newindex1 = -1;
+int16_t fs_index = -1;
+int16_t fs_index_block = -1;
+int16_t fs_index_record = -1;
+int16_t fs_index_sector = -1;
+int16_t fs_index_fileid = -1;
+
+int16_t fs_page = -1;
+uint8_t fs_page_flags = 0;
+int16_t fs_page_sectors[N_FILES_ON_PAGE] = {[0 ... (N_FILES_ON_PAGE-1)] = -1};
+int16_t fs_page_fileids[N_FILES_ON_PAGE] = {[0 ... (N_FILES_ON_PAGE-1)] = -1};
+uint8_t fs_page_names[N_FILES_ON_PAGE][N_NAME+1] = {[0 ... (N_FILES_ON_PAGE-1)] = {[0 ... N_NAME] = 0}};
+int16_t fs_page_indexes[N_FILES_ON_PAGE] = {[0 ... (N_FILES_ON_PAGE-1)] = -1};
+int16_t fs_page_indexblocks[N_FILES_ON_PAGE] = {[0 ... (N_FILES_ON_PAGE-1)] = -1};
+int16_t fs_page_indexrecords[N_FILES_ON_PAGE] = {[0 ... (N_FILES_ON_PAGE-1)] = -1};
+
+volatile uint16_t fs_timeout;
+
+inline void fs_watchdog (void)
+{
+ ++fs_timeout;
+}
+
+
+/* SPI FLASH HANDLING */
+
+inline uint8_t fs_spi_1b (const uint8_t data) // send & receive single byte
+{
+ FS__SDR = data;
+ while (FS__SSR & 0x0040)
+ {}
+ return (uint8_t)(FS__SDR );
+}
+
+void fs_spi( // execute single command
+ const uint8_t opcode,
+ const uint16_t address_bytes,
+ const uint16_t dummy_bytes,
+ const uint16_t data_bytes,
+ const uint32_t address,
+ uint8_t * const read_data,
+ const uint8_t * const write_data,
+ const uint8_t flag
+)
+{
+ uint16_t i;
+ uint8_t io = 0;
+
+ // clear errors
+ if (FS__SSR & 0b00000111)
+ FS__SIR = FS__SSR;
+
+ // Chip Select & LED indicator
+ LED_U = 1;
+ FS_CS = 0;
+
+ io = fs_spi_1b(opcode);
+
+ for (i = address_bytes ? 2 : -1; i<3; --i) //assume 3 or 0 bytes
+ {
+ io = fs_spi_1b(*(((uint8_t *)(&address))+i));
+ }
+
+ for (i=0; i<dummy_bytes; ++i)
+ {
+ io = fs_spi_1b(io);
+ }
+
+ for (i=0; i<data_bytes; ++i)
+ {
+ if (flag & FS_WRITE_FLAG)
+ io = write_data[i];
+ else
+ io = 0;
+ io = fs_spi_1b(io);
+ if (flag & FS_READ_FLAG)
+ read_data[i] = io;
+ }
+
+ // Chip Select & LED indicator
+ FS_CS = 1;
+ LED_U = 0;
+}
+
+/* SPI FLASH COMMANDS */
+
+inline void fs_spi_read2 (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+)
+{
+ fs_spi(FS_READ_2, 3, 2, n, address, data, FS_NULL, FS_READ_FLAG);
+}
+
+inline void fs_spi_read1 (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+)
+{
+ fs_spi(FS_READ_1, 3, 1, n, address, data, FS_NULL, FS_READ_FLAG);
+}
+
+inline void fs_spi_read (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+)
+{
+ fs_spi(FS_READ, 3, 0, n, address, data, FS_NULL, FS_READ_FLAG);
+}
+
+inline void fs_spi_erase_4k (const uint32_t address)
+{
+ fs_spi(FS_ERASE_4K, 3, 0, 0, address, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_erase_32k (const uint32_t address)
+{
+ fs_spi(FS_ERASE_32K, 3, 0, 0, address, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_erase_64k (const uint32_t address)
+{
+ fs_spi(FS_ERASE_64K, 3, 0, 0, address, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_erase_chip (void)
+{
+ fs_spi(FS_ERASE_CHIP, 0, 0, 0, 0, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_program (
+ const uint32_t address,
+ const uint16_t n,
+ const uint8_t * const data
+)
+{
+ fs_spi(FS_PROGRAM, 3, 0, n, address, FS_NULL, data, FS_WRITE_FLAG);
+}
+
+inline void fs_spi_write_enable (void)
+{
+ fs_spi(FS_WRITE_ENABLE, 0, 0, 0, 0, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_write_disable (void)
+{
+ fs_spi(FS_WRITE_DISABLE, 0, 0, 0, 0, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_protect_sector (const uint32_t address)
+{
+ fs_spi(FS_PROTECT_SECTOR, 3, 0, 0, address, FS_NULL, FS_NULL, 0);
+}
+
+inline void fs_spi_unprotect_sector (const uint32_t address)
+{
+ fs_spi(FS_UNPROTECT_SECTOR, 3, 0, 0, address, FS_NULL, FS_NULL, 0);
+}
+
+inline uint8_t fs_spi_read_sector_protection (const uint32_t address)
+{
+ uint8_t status;
+ fs_spi(FS_READ_SECTOR_PROTECTION, 3, 0, 1, address, &status, FS_NULL, FS_READ_FLAG);
+ return status;
+}
+
+inline uint16_t fs_spi_read_status (void)
+{
+ uint16_t status;
+ fs_spi(FS_READ_STATUS, 0, 0, 2, 0, (uint8_t*)&status, FS_NULL, FS_READ_FLAG);
+ return status;
+}
+
+inline void fs_spi_write_status_low (const uint8_t status)
+{
+ fs_spi(FS_WRITE_STATUS_1, 0, 0, 1, 0, FS_NULL, &status, FS_WRITE_FLAG);
+}
+
+inline void fs_spi_write_status_high (const uint8_t status)
+{
+ fs_spi(FS_WRITE_STATUS_2, 0, 0, 1, 0, FS_NULL, &status, FS_WRITE_FLAG);
+}
+
+inline void fs_spi_write_status (const uint16_t status)
+{
+ fs_spi_write_status_low((uint8_t) status);
+ fs_spi_write_status_high(*(((uint8_t*)(&status))+1));
+}
+
+inline void fs_spi_reset (void)
+{
+ uint8_t confirm = FS_RESET_CONFIRM;
+ fs_spi(FS_RESET, 0, 0, 1, 0, FS_NULL, &confirm, FS_WRITE_FLAG);
+}
+
+inline uint32_t fs_spi_read_id (void) // TODO: fix this if ever needed
+{
+ uint32_t id = 0;
+ fs_spi(FS_READ_ID, 0, 0, 3, 0, (uint8_t*)&id, FS_NULL, FS_READ_FLAG);
+ return id;
+}
+
+inline void fs_wait_ready (const uint16_t timeout)
+{
+ uint16_t status;
+
+ fs_timeout = 0;
+ do
+ {
+ if (fs_timeout > timeout)
+ {
+ fs_index = -1;
+ fs_index0 = -1;
+ fs_index1 = -1;
+ debug_string("FS TIMEOUT!\r\n",1);
+ gui_trigger_error(GUI_ERRF_FS);
+ break;
+ }
+ status = fs_spi_read_status();
+ }while(status & FS_BSY);
+}
+
+/* support for filesystem operations */
+
+inline uint32_t fs_expand_address (
+ const uint8_t sector,
+ const uint8_t id,
+ const uint16_t offset
+)
+{
+ return
+ ((((uint32_t)sector)<<(FILEID_BITS+FILE_BITS)) |
+ (((uint32_t)id)<<FILE_BITS))
+ +offset;
+}
+
+inline uint32_t fs_expand_record_address (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record
+)
+{
+ uint8_t index_sector;
+
+ if (index & NEW_INDEX)
+ index_sector = (index & 1) ? fs_newindex1 : fs_newindex0;
+ else
+ index_sector = (index & 1) ? fs_index1 : fs_index0;
+
+ return fs_expand_address(
+ index_sector,
+ block,
+ ((uint16_t)record) * N_RECORD_BYTES + INDEX_OFFSET_RECORDS
+ );
+}
+
+inline uint8_t fs_is_sector_free (const uint8_t sector)
+{
+ uint32_t address;
+ uint8_t data;
+
+ address = fs_expand_address(sector, 0, FILE_OFFSET_FLAG);
+ fs_spi_read (address, 1, &data);
+
+ return (data == 0xff) ? 0xff : 0x00;
+}
+
+inline uint8_t fs_is_file_free (
+ const uint8_t sector,
+ const uint8_t id
+)
+{
+ uint32_t address;
+ uint8_t data;
+
+ address = fs_expand_address(sector, 0, FILE_OFFSET_FLAG);
+ fs_spi_read (address, 1, &data);
+
+ return data & (1<<id);
+}
+
+uint16_t fs_get_file_type (
+ const uint8_t sector,
+ const uint8_t id
+)
+{
+ uint32_t address;
+ uint16_t type = 0;
+ uint8_t free;
+
+ free = fs_is_file_free(sector, id);
+ address = fs_expand_address(sector, id, FILE_OFFSET_TYPE);
+ fs_spi_read (address, 1, (uint8_t*)&type);
+
+ if(free)
+ {
+ if(type != FILE_FREE)
+ type |= FILE_INVALID;
+ }
+ else
+ {
+ if(type == FILE_FREE)
+ type |= FILE_INVALID;
+ }
+ return type;
+}
+
+inline uint16_t fs_get_index_validation (const uint8_t sector)
+{
+ uint16_t type;
+
+ type = fs_get_file_type(sector, 0);
+ if ((type != FILE_INDEX_0)&&(type != FILE_INDEX_1))
+ return 0;
+ if ((fs_get_file_type(sector, 1)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 2)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 3)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 4)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 5)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 6)!=type))
+ return 0;
+ if ((fs_get_file_type(sector, 7)!=type))
+ return 0;
+ return type;
+}
+
+/* filesystem indexing */
+
+inline void fs_locate_index (void)
+{
+ int16_t i;
+ uint8_t found0 = 0;
+ uint8_t found1 = 0;
+ uint16_t type;
+
+ for (i=0; i< N_SECTORS; ++i)
+ {
+ type = fs_get_index_validation(i);
+
+ if (type == FILE_INDEX_0)
+ {
+ found0 = 1;
+ fs_index0 = i;
+ }
+ else if (type == FILE_INDEX_1)
+ {
+ found1 = 1;
+ fs_index1 = i;
+ }
+
+ if (found0 && found1)
+ return;
+ }
+ fs_index0 = -1;
+ fs_index1 = -1;
+}
+
+void fs_scan_index (void)
+{
+ uint8_t index, block, record;
+ uint8_t status, page, id, sector=fs_index0, fileid=N_FILES_IN_SECTOR-1;
+ uint8_t lastsector, lastfileid;
+
+ for (index = 0; index<2; ++index)
+ {
+ for (block = 0; block < N_FILES_IN_SECTOR; ++block)
+ {
+ for (record = 0; record < N_INDEX_RECORDS; ++record)
+ {
+ lastsector = sector;
+ lastfileid = fileid;
+ status = fs_read_record(
+ index, block, record,
+ &page, &id,
+ §or, &fileid
+ );
+ if (status == RECORD_FREE)
+ goto fs_scan_index__after_scan;
+ }
+ }
+ }
+ fs_scan_index__after_scan:
+
+ fs_index = index;
+ fs_index_block = block;
+ fs_index_record = record;
+ fs_index_sector = lastsector;
+ fs_index_fileid = lastfileid;
+ fs_index_next_file();
+}
+
+inline void fs_index_next_record (void)
+{
+ if (fs_index_record < N_INDEX_RECORDS-1)
+ ++fs_index_record;
+ else
+ {
+ fs_index_record = 0;
+ if (fs_index_block < N_FILES_IN_SECTOR-1)
+ ++fs_index_block;
+ else
+ {
+ fs_index_block = 0;
+ if(fs_index < 1)
+ ++fs_index;
+ else
+ {
+ fs_index = -1;
+ fs_index0 = -1;
+ fs_index1 = -1;
+ debug_string("FS OVERFLOW!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_FS);
+ }
+ }
+ }
+}
+
+inline void fs_index_next_sector (void)
+{
+ fs_index_fileid = 0;
+ if (fs_index_sector < N_SECTORS - 1)
+ ++fs_index_sector;
+ else
+ fs_index_sector = 0;
+}
+
+inline void fs_index_next_file (void)
+{
+ if (fs_index_fileid < N_FILES_IN_SECTOR-1)
+ ++fs_index_fileid;
+ else
+ fs_index_next_sector();
+}
+
+/* filesystem operations, low level */
+
+uint8_t fs_create_file (
+ const uint8_t sector,
+ const uint8_t id,
+ const uint8_t type
+)
+{
+ uint32_t sector_address;
+ uint32_t file_id_address;
+ uint8_t flag;
+
+ // debug_string("create file ",1);
+ // debug_hex(type,1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(sector,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(id,1,1,0);
+ // debug_string("\r\n",1);
+
+ if (!fs_is_file_free(sector, id))
+ return 0;
+
+ sector_address = fs_expand_address(sector, 0, FILE_OFFSET_FLAG);
+ file_id_address = fs_expand_address(sector, id, FILE_OFFSET_TYPE);
+ flag = ~(1<<id);
+
+ // debug_string("sector_addr: ",1);
+ // debug_hex(sector_address,1,8,1);
+ // debug_string(" flag: ",1);
+ // debug_hex(flag,1,2,0);
+ // debug_string("\r\nfile_id_addr: ",1);
+ // debug_hex(file_id_address,1,8,1);
+ // debug_string(" type: ",1);
+ // debug_hex(type,1,2,0);
+ // debug_string("\r\n",1);
+
+ fs_spi_write_enable();
+ fs_spi_program(sector_address, 1, &flag);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+ fs_spi_write_enable();
+ fs_spi_program(file_id_address, 1, &type);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+
+ return 0xff;
+}
+
+uint8_t fs_delete_file (
+ const uint8_t sector,
+ const uint8_t id
+)
+{
+ uint32_t sector_address;
+ uint32_t file_id_address;
+ uint8_t flag;
+ uint8_t type = FILE_DELETED;
+
+ sector_address = fs_expand_address(sector, 0, FILE_OFFSET_FLAG);
+ file_id_address = fs_expand_address(sector, id, FILE_OFFSET_TYPE);
+ flag = ~(1<<id);
+
+ // debug_string("delete file ",1);
+ // debug_hex(type,1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(sector,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(id,1,1,0);
+ // debug_string("\r\nsector_addr: ",1);
+ // debug_hex(sector_address,1,8,1);
+ // debug_string(" flag: ",1);
+ // debug_hex(flag,1,2,0);
+ // debug_string("\r\nfile_id_addr: ",1);
+ // debug_hex(file_id_address,1,8,1);
+ // debug_string(" type: ",1);
+ // debug_hex(type,1,2,0);
+ // debug_string("\r\n",1);
+
+ fs_spi_write_enable();
+ fs_spi_program(sector_address, 1, &flag);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+ fs_spi_write_enable();
+ fs_spi_program(file_id_address, 1, &type);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+
+ return 0xff;
+}
+
+uint8_t fs_duplicate_file (
+ const uint8_t src_sector,
+ const uint8_t src_id,
+ const uint8_t dst_sector,
+ const uint8_t dst_id
+)
+{
+ uint32_t src_address_0, src_address_1;
+ uint32_t dst_address_0, dst_address_1;
+ uint32_t dst_sector_address;
+ uint8_t data[256];
+
+ // debug_string("duplicate file ",1);
+ // debug_byte(' ',1);
+ // debug_hex(src_sector,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(src_id,1,1,0);
+ // debug_byte(' ',1);
+ // debug_hex(dst_sector,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(dst_id,1,1,0);
+ // debug_string("\r\n",1);
+
+ if (!fs_is_file_free(dst_sector, dst_id))
+ return 0;
+
+ src_address_0 = fs_expand_address(src_sector, src_id, 0);
+ src_address_1 = src_address_0 + 256;
+ dst_address_0 = fs_expand_address(dst_sector, dst_id, 0);
+ dst_address_1 = dst_address_0 + 256;
+ dst_sector_address = fs_expand_address(dst_sector, 0, FILE_OFFSET_FLAG);
+
+ // debug_string("src_addr: ",1);
+ // debug_hex(src_address_0,1,8,1);
+ // debug_byte(' ',1);
+ // debug_hex(src_address_1,1,8,1);
+ // debug_string("\r\ndst_addr: ",1);
+ // debug_hex(dst_address_0,1,8,1);
+ // debug_byte(' ',1);
+ // debug_hex(dst_address_1,1,8,1);
+ // debug_string("\r\ndst_sect_addr: ",1);
+ // debug_hex(dst_sector_address,1,8,1);
+ // debug_string("\r\n",1);
+
+ fs_spi_read(src_address_0, 256, data);
+ data[FILE_OFFSET_FLAG] = ~ (1<<dst_id);
+ fs_spi_write_enable();
+ fs_spi_program(dst_sector_address, 1, data+FILE_OFFSET_FLAG);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+ fs_spi_write_enable();
+ fs_spi_program(dst_address_0, 256, data);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+ fs_spi_read(src_address_1, 256, data);
+ fs_spi_write_enable();
+ fs_spi_program(dst_address_1, 256, data);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+ fs_spi_write_disable();
+
+ return 0xff;
+}
+
+inline void fs_erase_sector(const uint8_t sector)
+{
+ uint32_t address;
+
+ address = fs_expand_address(sector, 0, 0);
+
+ // debug_string("erase sector ",1);
+ // debug_hex(sector,1,2,0);
+ // debug_string("\r\n",1);
+
+ fs_spi_write_enable();
+ fs_spi_erase_4k(address);
+ fs_wait_ready(TIMEOUT_ERASE);
+}
+
+void fs_format (void)
+{
+ uint16_t status;
+
+ fs_spi_write_enable ();
+ fs_spi_erase_chip();
+ fs_wait_ready(TIMEOUT_FORMAT);
+
+ if(fs_index0 < 0)
+ {
+ fs_index0 = 0;
+ fs_index1 = 1;
+ }
+ else
+ {
+ ++fs_index0;
+ if (fs_index0 >= N_SECTORS - 1)
+ fs_index0 = 0;
+ fs_index1 = fs_index0 + 1;
+ }
+
+ fs_create_file(fs_index0, 0, FILE_INDEX_0);
+ fs_create_file(fs_index0, 1, FILE_INDEX_0);
+ fs_create_file(fs_index0, 2, FILE_INDEX_0);
+ fs_create_file(fs_index0, 3, FILE_INDEX_0);
+ fs_create_file(fs_index0, 4, FILE_INDEX_0);
+ fs_create_file(fs_index0, 5, FILE_INDEX_0);
+ fs_create_file(fs_index0, 6, FILE_INDEX_0);
+ fs_create_file(fs_index0, 7, FILE_INDEX_0);
+
+ fs_create_file(fs_index1, 0, FILE_INDEX_1);
+ fs_create_file(fs_index1, 1, FILE_INDEX_1);
+ fs_create_file(fs_index1, 2, FILE_INDEX_1);
+ fs_create_file(fs_index1, 3, FILE_INDEX_1);
+ fs_create_file(fs_index1, 4, FILE_INDEX_1);
+ fs_create_file(fs_index1, 5, FILE_INDEX_1);
+ fs_create_file(fs_index1, 6, FILE_INDEX_1);
+ fs_create_file(fs_index1, 7, FILE_INDEX_1);
+}
+
+uint8_t fs_read_record (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record,
+ uint8_t * const page,
+ uint8_t * const id,
+ uint8_t * const sector,
+ uint8_t * const fileid
+)
+{
+ uint8_t status;
+ uint32_t address;
+ uint8_t data[N_RECORD_BYTES];
+
+ address = fs_expand_record_address(index, block, record);
+
+ fs_spi_read(address, N_RECORD_BYTES, data);
+
+ status = data[RECORD_OFFSET_ID] & RECORD_FLAGS;
+ if (status == RECORD_ACTIVE)
+ {
+ *page = data[RECORD_OFFSET_PAGE];
+ *id =(data[RECORD_OFFSET_ID] & PAGEID_MASK) >> PAGEID_SHIFT;
+ *sector= data[RECORD_OFFSET_SECTOR];
+ *fileid=(data[RECORD_OFFSET_ID] & SECTRID_MASK) >> SECTRID_SHIFT;
+ }
+ return status;
+}
+
+void fs_write_record (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record,
+ const uint8_t page,
+ const uint8_t id,
+ const uint8_t sector,
+ const uint8_t fileid
+)
+{
+ uint32_t address;
+ uint8_t data[N_RECORD_BYTES];
+
+ // debug_string("write record ",1);
+ // debug_hex(index,1,1,0);
+ // debug_byte(':',1);
+ // debug_hex(block,1,1,0);
+ // debug_byte(':',1);
+ // debug_hex(record,1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(page,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(id,1,1,0);
+ // debug_byte(' ',1);
+ // debug_hex(sector,1,2,0);
+ // debug_byte(':',1);
+ // debug_hex(fileid,1,1,0);
+ // debug_string("\r\n",1);
+
+ address = fs_expand_record_address(index, block, record);
+
+ data [RECORD_OFFSET_ID] =
+ ((id << PAGEID_SHIFT) & PAGEID_MASK) |
+ ((fileid << SECTRID_SHIFT) & SECTRID_MASK) |
+ (RECORD_FLAGS & RECORD_ACTIVE);
+ data [RECORD_OFFSET_SECTOR] = sector;
+ data [RECORD_OFFSET_PAGE] = page;
+
+ // debug_string("record_addr: ",1);
+ // debug_hex(address,1,8,1);
+ // debug_string(" data: ",1);
+ // debug_hex(data[0],1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(data[1],1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(data[2],1,2,0);
+ // debug_string("\r\n",1);
+
+ fs_spi_write_enable();
+ fs_spi_program(address, N_RECORD_BYTES, data);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+}
+
+void fs_delete_record (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record
+)
+{
+ uint32_t address;
+ uint8_t data[N_RECORD_BYTES] = {[0 ... (N_RECORD_BYTES-1)] = RECORD_DELETED};
+
+ // debug_string("delete record ",1);
+ // debug_hex(index,1,1,0);
+ // debug_byte(':',1);
+ // debug_hex(block,1,1,0);
+ // debug_byte(':',1);
+ // debug_hex(record,1,2,0);
+ // debug_string("\r\n",1);
+
+ address = fs_expand_record_address(index, block, record);
+
+ // debug_string("record_addr: ",1);
+ // debug_hex(address,1,8,1);
+ // debug_string(" data: ",1);
+ // debug_hex(data[0],1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(data[1],1,2,0);
+ // debug_byte(' ',1);
+ // debug_hex(data[2],1,2,0);
+ // debug_string("\r\n",1);
+
+ fs_spi_write_enable();
+ fs_spi_program(address, N_RECORD_BYTES, data);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+}
+
+/* filesystem operations, high level */
+
+void fs_get_file_name (
+ const uint8_t sector,
+ const uint8_t id,
+ uint8_t * const name
+)
+{
+ uint32_t address;
+
+ address = fs_expand_address(sector, id, FILE_OFFSET_NAME);
+ fs_spi_read(address, N_NAME, name);
+}
+
+void fs_load_page (const uint8_t new_page)
+{
+ uint8_t index, block, record;
+ uint8_t status, page, id, sector, fileid;
+
+ // debug_string("FS LOAD PAGE\r\n",1);
+
+ if (new_page == fs_page)
+ {
+ // debug_string("no change\r\n",1);
+ return;
+ }
+
+ fs_page = -1;
+ fs_page_flags = 0;
+ for (id = 0; id < N_FILES_ON_PAGE; ++id)
+ fs_page_names[id][0] = '\0';
+
+ if ((fs_index0 < 0) || (fs_index1 < 0))
+ {
+ // debug_string("no index\r\n",1);
+ return;
+ }
+
+ for (index = 0; index<2; ++index)
+ {
+ for (block = 0; block < N_FILES_IN_SECTOR; ++block)
+ {
+ for (record = 0; record < N_INDEX_RECORDS; ++record)
+ {
+ // debug_string("i=",1);
+ // debug_dec(index,1,1);
+ // debug_string(" b=",1);
+ // debug_dec(block,1,1);
+ // debug_string(" r=",1);
+ // debug_dec(record,1,3);
+ // debug_string(" : ",1);
+
+ status = fs_read_record(
+ index, block, record,
+ &page, &id,
+ §or, &fileid
+ );
+ // debug_hex(status,1,2,0);
+ // debug_string("\r\n",1);
+
+ if (status == RECORD_FREE)
+ goto fs_load_page__after_scan;
+ if (status != RECORD_ACTIVE)
+ continue;
+ if (page == new_page)
+ {
+ fs_page_indexes[id] = index;
+ fs_page_indexblocks[id] = block;
+ fs_page_indexrecords[id] = record;
+ fs_page_sectors[id] = sector;
+ fs_page_fileids[id] = fileid;
+ fs_get_file_name(sector, fileid, fs_page_names[id]);
+ fs_page_flags |= 1<<id;
+ if (fs_page_flags == PAGE_FLAGS)
+ goto fs_load_page__after_scan;
+ }
+ }
+ }
+ }
+ fs_load_page__after_scan:
+ // for (id = 0; id < FILES_ON_PAGE; ++i)
+ // {
+ // if (!(fs_page_flags & (1<<id)))
+ // fs_page_names[id][0] = '\0';
+ // }
+ fs_page = new_page;
+}
+
+void fs_store_voice (
+ const uint8_t id,
+ const uint8_t * const name,
+ const uint32_t A,
+ const uint32_t D,
+ const uint32_t S,
+ const uint32_t R,
+ const uint8_t * const wave
+)
+{
+ uint8_t overwrite;
+ int16_t i;
+ uint32_t address;
+ uint8_t data[FILE_OFFSET_NAME - FILE_OFFSET_START];
+ uint8_t opt_sector;
+
+ if ((fs_index0 < 0) || (fs_index1 < 0))
+ return;
+
+ overwrite = fs_page_flags & (1<<id);
+
+ for (i=0; ;++i)
+ {
+ if (i >= (N_SECTORS * N_FILES_IN_SECTOR))
+ {
+ fs_index = -1;
+ fs_index0 = -1;
+ fs_index1 = -1;
+ debug_string("FS FULL!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_FS);
+ return;
+ }
+ if (fs_create_file(fs_index_sector, fs_index_fileid, FILE_NORMAL))
+ break;
+ fs_index_next_file();
+ }
+ address = fs_expand_address(fs_index_sector, fs_index_fileid, 0);
+
+ data[FILE_OFFSET_PAGE - FILE_OFFSET_START] = fs_page;
+ data[FILE_OFFSET_ID - FILE_OFFSET_START] = id;
+ *((uint32_t*)&(data[FILE_OFFSET_ADSR + FILE_OFFSET_ADSR_A - FILE_OFFSET_START])) = A;
+ *((uint32_t*)&(data[FILE_OFFSET_ADSR + FILE_OFFSET_ADSR_D - FILE_OFFSET_START])) = D;
+ *((uint32_t*)&(data[FILE_OFFSET_ADSR + FILE_OFFSET_ADSR_S - FILE_OFFSET_START])) = S;
+ *((uint32_t*)&(data[FILE_OFFSET_ADSR + FILE_OFFSET_ADSR_R - FILE_OFFSET_START])) = R;
+
+ fs_spi_write_enable();
+ fs_spi_program(address + FILE_OFFSET_START, FILE_OFFSET_NAME - FILE_OFFSET_START, data);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+
+ fs_spi_write_enable();
+ fs_spi_program(address + FILE_OFFSET_NAME, N_NAME, name);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+
+ fs_spi_write_enable();
+ fs_spi_program(address + FILE_OFFSET_WAVE, N_SAMPLE, wave);
+ fs_wait_ready(TIMEOUT_PROGRAM);
+
+
+ if (overwrite)
+ {
+ fs_delete_record(
+ fs_page_indexes[id],
+ fs_page_indexblocks[id],
+ fs_page_indexrecords[id]
+ );
+ fs_delete_file(
+ fs_page_sectors[id],
+ fs_page_fileids[id]
+ );
+ opt_sector = fs_page_sectors[id];
+ }
+
+ fs_write_record(
+ fs_index,
+ fs_index_block,
+ fs_index_record,
+ fs_page,
+ id,
+ fs_index_sector,
+ fs_index_fileid
+ );
+
+ fs_page_flags |= 1<<id;
+ fs_page_indexes[id] = fs_index;
+ fs_page_indexblocks[id] = fs_index_block;
+ fs_page_indexrecords[id] = fs_index_record;
+ fs_page_sectors[id] = fs_index_sector;
+ fs_page_fileids[id] = fs_index_fileid;
+ memcpy(fs_page_names[id],name, N_NAME);
+
+ fs_index_next_file();
+ fs_index_next_record();
+
+ if (overwrite)
+ fs_optimise_sector(opt_sector);
+
+ fs_optimise_index();
+}
+
+uint8_t fs_load_voice (
+ const uint8_t id,
+ uint32_t * const A,
+ uint32_t * const D,
+ uint32_t * const S,
+ uint32_t * const R,
+ uint8_t * const wave
+)
+{
+ int16_t i;
+ uint32_t address;
+ uint8_t data[FILE_OFFSET_NAME - FILE_OFFSET_ADSR];
+
+ if ((fs_index0 < 0) || (fs_index1 < 0))
+ return 0;
+
+ if (!(fs_page_flags & (1<<id)))
+ return 0;
+
+ address = fs_expand_address(fs_page_sectors[id], fs_page_fileids[id], 0);
+
+ fs_spi_read(address + FILE_OFFSET_ADSR, FILE_OFFSET_NAME - FILE_OFFSET_ADSR, data);
+
+ *A = *((uint32_t*)&(data[FILE_OFFSET_ADSR_A]));
+ *D = *((uint32_t*)&(data[FILE_OFFSET_ADSR_D]));
+ *S = *((uint32_t*)&(data[FILE_OFFSET_ADSR_S]));
+ *R = *((uint32_t*)&(data[FILE_OFFSET_ADSR_R]));
+
+ fs_spi_read(address + FILE_OFFSET_WAVE, N_SAMPLE, wave);
+
+ return 0xff;
+}
+
+void fs_optimise_sector (const uint8_t opt_sector)
+{
+ uint8_t found = 0;
+ uint8_t deleted = 0;
+ uint8_t index, block, record;
+ uint8_t status, page, id, sector, fileid;
+ uint16_t type, i;
+
+ uint8_t pages[N_FILES_IN_SECTOR];
+ uint8_t ids[N_FILES_IN_SECTOR];
+ uint8_t types[N_FILES_IN_SECTOR];
+ uint8_t indexes[N_FILES_IN_SECTOR];
+ uint8_t indexblocks[N_FILES_IN_SECTOR];
+ uint8_t indexrecords[N_FILES_IN_SECTOR];
+
+ uint32_t address;
+
+ // debug_string("optimise_sector ", 1);
+ // debug_hex(opt_sector, 1, 2, 0);
+ // debug_string("\r\n",1);
+
+ for (fileid = 0; fileid < N_FILES_IN_SECTOR; ++fileid)
+ {
+ type = fs_get_file_type(opt_sector, fileid);
+ // debug_hex(fileid, 1,1,0);
+ // debug_byte(':',1);
+ // debug_hex(type, 1,2,0);
+ if (type != FILE_NORMAL)
+ {
+ types[fileid] = FILE_DELETED;
+ found |= (1<<fileid);
+ if(type != FILE_FREE)
+ {
+ ++deleted;
+ // debug_byte('+',1);
+ }
+ }
+ else
+ types[fileid] = type;
+ // debug_byte(' ',1);
+ }
+
+ // debug_string("\r\n deleted=",1);
+ // debug_hex(deleted,1,1,0);
+ // debug_string("\r\n",1);
+
+ if (deleted <= N_MAX_DELETED)
+ return;
+
+ if (fs_page >= 0)
+ {
+ for (id = 0; id < N_FILES_ON_PAGE; ++id)
+ {
+ if (fs_page_sectors[id] == opt_sector)
+ {
+ fileid = fs_page_fileids[id];
+ found |= (1<<fileid);
+ pages[fileid] = fs_page;
+ ids[fileid] = id;
+ indexes[fileid] = fs_page_indexes[id];
+ indexblocks[fileid] = fs_page_indexblocks[id];
+ indexrecords[fileid] = fs_page_indexrecords[id];
+ }
+ }
+ }
+
+ if (found == SECTOR_FLAGS)
+ goto fs_optimise_sector__after_scan;
+
+ for (index = 0; index < 2; ++index)
+ {
+ for (block = 0; block < N_FILES_IN_SECTOR; ++block)
+ {
+ for (record = 0; record < N_INDEX_RECORDS; ++record)
+ {
+ status = fs_read_record(
+ index, block, record,
+ &page, &id,
+ §or, &fileid
+ );
+ if (status == RECORD_FREE)
+ goto fs_optimise_sector__after_scan;
+ else if ((status == RECORD_ACTIVE) && (sector == opt_sector))
+ {
+ found |= (1<<fileid);
+ pages[fileid] = page;
+ ids[fileid] = id;
+ indexes[fileid] = index;
+ indexblocks[fileid] = block;
+ indexrecords[fileid] = record;
+ if (found == SECTOR_FLAGS)
+ goto fs_optimise_sector__after_scan;
+ }
+ }
+ }
+ }
+ fs_optimise_sector__after_scan:
+
+ // debug_string("found=",1);
+ // debug_hex(found,1,2,0);
+ // debug_string("\r\n",1);
+
+ if (opt_sector == fs_index_sector)
+ fs_index_next_sector();
+
+ for (fileid = 0; fileid < N_FILES_IN_SECTOR; ++fileid)
+ {
+ if ((found & (1<<fileid)) && (types[fileid]==FILE_NORMAL))
+ {
+ for (i = 0; ; ++i)
+ {
+ if (i >= (N_SECTORS * N_FILES_IN_SECTOR))
+ {
+ fs_index = -1;
+ fs_index0 = -1;
+ fs_index1 = -1;
+ debug_string("FS FULL!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_FS);
+ return;
+ }
+ if (fs_duplicate_file(opt_sector, fileid, fs_index_sector, fs_index_fileid))
+ break;
+ fs_index_next_file();
+ }
+ fs_write_record(
+ fs_index, fs_index_block, fs_index_record,
+ pages[fileid], ids[fileid],
+ fs_index_sector, fs_index_fileid
+ );
+ fs_delete_record(indexes[fileid], indexblocks[fileid], indexrecords[fileid]);
+ if (pages[fileid] == fs_page)
+ {
+ id = ids[fileid];
+ fs_page_indexes[id] = fs_index;
+ fs_page_indexblocks[id] = fs_index_block;
+ fs_page_indexrecords[id] = fs_index_record;
+ fs_page_sectors[id] = fs_index_sector;
+ fs_page_fileids[id] = fs_index_fileid;
+ }
+ fs_index_next_record();
+ fs_index_next_file();
+ }
+ }
+
+ fs_erase_sector(opt_sector);
+}
+
+void fs_optimise_index (void)
+{
+ uint16_t i;
+ uint8_t index=0, block=0, record=0;
+ uint8_t newindex=0, newblock=0, newrecord=0;
+ uint8_t status, page, id, sector, fileid;
+
+ if (!(
+ (fs_index == 1) &&
+ (fs_index_block == N_FILES_IN_SECTOR-1) &&
+ (fs_index_record >= N_INDEX_RECORDS - N_INDEX_MARGIN)
+ ))
+ return;
+ if ((fs_index0 < 0) || (fs_index1 < 0))
+ return;
+
+ // debug_string("optimise_index\r\n", 1);
+
+ fs_newindex0 = -1;
+ fs_newindex1 = -1;
+ sector = fs_index_sector;
+
+ for (i = 0; i< N_SECTORS ; ++i)
+ {
+ if (fs_is_sector_free(sector))
+ {
+ if (fs_newindex0 <0)
+ fs_newindex0 = sector;
+ else
+ {
+ fs_newindex1 = sector;
+ break;
+ }
+ }
+ if (sector >= N_SECTORS-1)
+ sector = 0;
+ else
+ ++sector;
+ }
+ if (fs_newindex1 < 0)
+ {
+ fs_index = -1;
+ fs_index0 = -1;
+ fs_index1 = -1;
+ debug_string("FS FULL!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_FS);
+ return;
+ }
+
+ for (id =0; id<N_FILES_IN_SECTOR; ++id)
+ {
+ fs_create_file(fs_newindex0, id, FILE_INDEX_0);
+ fs_create_file(fs_newindex1, id, FILE_INDEX_1);
+ }
+
+ for (index=0; index<2; ++i)
+ {
+ for (block=0; block<N_FILES_IN_SECTOR; ++block)
+ {
+ for (record=0; record<N_INDEX_RECORDS; ++record)
+ {
+ status = fs_read_record(
+ index, block, record,
+ &page, &id,
+ §or, &fileid
+ );
+ if (status == RECORD_FREE)
+ goto fs_optimise_index__after_scan;
+ if (status != RECORD_ACTIVE)
+ continue;
+ fs_write_record(
+ newindex | NEW_INDEX, newblock, newrecord,
+ page, id,
+ sector, fileid
+ );
+ //todo: extract to sub?
+ if (newrecord < N_INDEX_RECORDS-1)
+ ++newrecord;
+ else
+ {
+ newrecord=0;
+ if(newblock < N_FILES_IN_SECTOR)
+ ++newblock;
+ else
+ {
+ newblock = 0;
+ ++newindex;
+ }
+ }
+ }
+ }
+ }
+ fs_optimise_index__after_scan:
+
+ fs_erase_sector(fs_index0);
+ fs_erase_sector(fs_index1);
+
+ fs_index0 = fs_newindex0;
+ fs_index1 = fs_newindex1;
+ fs_index = newindex;
+ fs_index_block = newblock;
+ fs_index_record = newrecord;
+}
+
+inline void setup_fs (void)
+{
+ FS_HOLD = 1;
+ FS_HOLD__PM = 0;
+ FS_HOLD = 1;
+
+ FS_WP = 1;
+ FS_WP__PM = 0;
+ FS_WP = 1;
+
+ FS_CS = 1;
+ FS_CS__PM = 0;
+ FS_CS__PU = 0;
+ FS_CS = 1;
+
+ LED_U = 0;
+ LED_U__PM = 0;
+
+ PER0 |= 0b00001000; //enable serial array unit 1
+
+ SPS1 = (SPS1 & 0xff0f) | 0x0000; //CK01 = fclk/1 = 32MHz
+
+ FS__SMR = 0b1000000000100000; //CK01, int. on tx end
+ FS__SCR = 0b1111000000000111; //T/R enable, mode 0, MSB first, 8 bit
+ FS__SDR = 0x0400; //32MHz / 6 = 5+1/3 MHz
+
+ SO1 &= ~0b0000001000000010; //ck, so = 0 (mode^!)
+
+ FS__SOE = 1;
+
+ FS_SCK__PM = 0;
+ FS_SCK__PU = 0;
+ FS_SCK = 1;
+
+ FS_MOSI__PM = 0;
+ FS_MOSI__PU = 0;
+ FS_MOSI = 1;
+
+ FS_MISO__PM = 1;
+ FS_MISO__POM = 0;
+ FS_MISO__PU = 0;
+
+ FS__SS = 1;
+}
+
+inline void init_fs (void)
+{
+ uint8_t index, block, record;
+ uint8_t status, page, id, sector, fileid;
+
+ fs_spi_write_disable ();
+
+ fs_locate_index();
+ if((fs_index0<0)||(fs_index1<0))
+ {
+ fs_index = -1;
+ debug_string("FS INVALID!\r\n", 1);
+ gui_trigger_error(GUI_ERRF_FS);
+ return;
+ }
+ fs_scan_index();
+
+ debug_string("INIT_FS\r\nindex0=",1);
+ debug_dec(fs_index0,1,1);
+ debug_string("\r\nindex1=",1);
+ debug_dec(fs_index1,1,1);
+ debug_string("\r\nindex=",1);
+ debug_dec(fs_index,1,1);
+ debug_string("\r\nblock=",1);
+ debug_dec(fs_index_block,1,1);
+ debug_string("\r\nrecord=",1);
+ debug_dec(fs_index_record,1,1);
+ debug_string("\r\nsector=",1);
+ debug_dec(fs_index_sector,1,1);
+ debug_string("\r\nfileid=",1);
+ debug_dec(fs_index_fileid,1,1);
+ debug_string("\r\n",1);
+
+ // debug_sector(fs_index0);
+ // debug_sector(fs_index1);
+}
+
+void debug_file (
+ const uint8_t sector,
+ const uint8_t id
+)
+{
+ uint32_t address;
+ uint16_t i, j;
+ uint8_t data[16];
+
+ address = fs_expand_address(sector,id,0);
+
+ debug_string ("file ",1);
+ debug_hex(sector,1,2,0);
+ debug_byte(':',1);
+ debug_hex(id,1,1,0);
+ debug_string("\r\n",1);
+ debug_hex(address,1,5,1);
+ debug_string("\r\n",1);
+
+ for(i=0; i<FILE_OFFSET_NEXT; i+=16, address+=16)
+ {
+ fs_spi_read(address,16,data);
+ for(j=0; j<16; ++j)
+ {
+ if(j)
+ debug_byte(' ',1);
+ debug_hex(data[j],1,2,0);
+ }
+ debug_string("\r\n",1);
+ }
+}
+
+void debug_sector (const uint8_t sector)
+{
+ uint8_t id;
+
+ for(id = 0; id < N_FILES_IN_SECTOR; ++id)
+ debug_file(sector,id);
+}
--- /dev/null
+/* STORAGE OF SETTINGS */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+
+// Our SPI flash memory is AT25DF081A-SSH-T
+
+// SPI flash opcodes
+
+#define FS_READ_2 0x1B
+#define FS_READ_1 0x0B
+#define FS_READ 0x03
+#define FS_READ_DUAL 0x3B
+
+#define FS_ERASE_4K 0x20
+#define FS_ERASE_32K 0x52
+#define FS_ERASE_64K 0xD8
+#define FS_ERASE_CHIP 0x60
+// #define FS_ERASE_CHIP 0xC7
+
+#define FS_PROGRAM 0x02
+#define FS_PROGRAM_DUAL 0xA2
+
+#define FS_WRITE_ENABLE 0x06
+#define FS_WRITE_DISABLE 0x04
+#define FS_PROTECT_SECTOR 0x36
+#define FS_UNPROTECT_SECTOR 0x39
+#define FS_READ_SECTOR_PROTECTION 0x3C
+
+#define FS_SECTOR_LOCKDOWN 0x33
+#define FS_FREEZE_SECTOR_LOCKDOWN 0x34
+#define FS_READ_SECTOR_LOCKDOWN 0x35
+#define FS_PROGRAM_OTP_SECURITY 0x9B
+#define FS_READ_OTP_SECURITY 0x77
+
+#define FS_READ_STATUS 0x05
+#define FS_WRITE_STATUS_1 0x01
+#define FS_WRITE_STATUS_2 0x31
+
+#define FS_RESET 0xF0
+#define FS_RESET_CONFIRM 0xD0
+#define FS_READ_ID 0x9F
+#define FS_POWER_DOWN 0xB9
+#define FS_POWER_RESUME 0xAB
+
+#define FS_READ_FLAG 0x01
+#define FS_WRITE_FLAG 0x02
+
+// SPI flash status bits
+
+#define FS_BSY 0x0001 // Busy Status
+#define FS_RDY FS_BSY // Ready Status (reversed)
+#define FS_WEL 0x0002 // Write Enable Latch Status
+#define FS_SWP 0x000C // Software Protection Status
+#define FS_WPP 0x0010 // Write Protect Pin Status
+#define FS_EPE 0x0020 // Erase/Program Error
+#define FS_SPRL 0x0080 // Sector Protection Registers Locked
+#define FS_BSY2 0x0100 // Busy Status
+#define FS_RDY2 FS_BSY2// Ready Status (reversed)
+#define FS_SLE 0x0800 // Sector Lockdown Enabled
+#define FS_RSTE 0x1000 // Reset Enabled
+
+#define FS_NULL ((uint8_t *)0x00100000) //address outside memory map
+
+/*
+ max wait times according to datasheet:
+
+ program page 3 ms
+ erase 4K 200 ms
+ erase chip 28 s
+
+ we will use higher timeouts
+*/
+
+#define TIMEOUT_PROGRAM 100
+#define TIMEOUT_ERASE 1000
+#define TIMEOUT_FORMAT 60000
+
+/*
+FILESYSTEM:
+1MB
+256 sectors
+
++-------+-----------+
+| 00000 | |
+| | SECTOR 0 |
+| 00FFF | |
++-------+-----------+
+| 01000 | |
+| | SECTOR 1 |
+| 01FFF | |
++-------+-----------+
+| ... |
++-------+-----------+
+| FF000 | |
+| | SECTOR 255|
+| FFFFF | |
++-------+-----------+
+
+SECTOR:
+4kB
+8 files
+
++-----+-----+----+
+| 000 |FLAGS| |
++-----+-----+ |
+| 001 | |
+| | FILE 0 |
+| 1FF | |
++-----+--------+-+
+| 200 |RESERVED| |
++-----+--------+ |
+| 201 | |
+| | FILE 1 |
+| 3FF | |
++-----+----------+
+| ... |
++-----+--------+-+
+| E00 |RESERVED| |
++-----+--------+ |
+| F01 | |
+| | FILE 7 |
+| FFF | |
++-----+----------+
+
+FLAGS:
+76543210
+1 - free
+0 - used
+
+FILE:
+512 bytes
+
++-----+---------+
+| 000 |RESERVED |
++-----+---------+
+| 001 |FILE TYPE|
++-----+---------+
+| 002 | |
+| | DATA |
+| 1FF | |
++-----+---------+
+
+VOICE CONFIG FILE:
+
++-----+---------+
+| 000 |RESERVED |
++-----+---------+
+| 001 |FILE TYPE|
++-----+---------+
+| 002 | PAGE |
++-----+---------+
+| 003 | ID |
++-----+---------+
+| 004 | |
+| | A |
+| 007 | |
++-----+---------+
+| 008 | |
+| | D |
+| 00B | |
++-----+---------+
+| 00C | |
+| | S |
+| 00F | |
++-----+---------+
+| 010 | |
+| | R |
+| 013 | |
++-----+---------+
+| 014 | |
+| | NAME |
+| 02F | |
++-----+---------+
+| 030 | |
+| |RESERVED |
+| 0FF | |
++-----+---------+
+| 100 | |
+| |WAVEFORM |
+| 1FF | |
++-----+---------+
+
+INDEX FILE:
+
++-----+----------+
+| 000 | RESERVED |
++-----+----------+
+| 001 |FILE TYPE |
++-----+----------+
+| 002 | |
+| | RECORD 0 |
+| 004 | |
++-----+----------+
+| 005 | |
+| | RECORD 1 |
+| 007 | |
++-----+----------+
+| ... |
++-----+----------+
+| 1fd | |
+| |RECORD 169|
+| 1FF | |
++-----+----------+
+
+INDEX LOGICALLY:
+
++---------+---------+------------+
+|SECTOR 0 | BLOCK 0 | RECORD 0 |
+| | | ... |
+| |(1 file) | RECORD 169 |
+| +---------+------------+
+| | BLOCK 1 | RECORD 170 |
+| | | ... |
+| |(1 file) | RECORD 339 |
+| +---------+------------+
+| | ... |
+| +---------+------------+
+| | BLOCK 7 | RECORD 1190|
+| | | ... |
+| |(1 file) | RECORD 1359|
++---------+---------+------------+
+|SECTOR 1 | BLOCK 8 | RECORD 1360|
+| | | ... |
+| |(1 file) | RECORD 1529|
+| +---------+------------+
+| | ... |
+| +---------+------------+
+| | BLOCK 15| RECORD 2550|
+| | | ... |
+| |(1 file) | RECORD 2719|
++---------+---------+------------+
+
+INDEX RECORD:
+
+ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
++---+---+---+---+---+---+---+---+---+
+| 0 | A |ID ON PAGE | B |ID IN SECTR|
++---+---+-----------+---+-----------+
+| 1 | SECTOR |
++---+-------------------------------+
+| 2 | PAGE |
++---+-------------------------------+
+
+AB:
+11 - record free
+01 - record active
+00 - record deleted
+
+*/
+
+#define N_SECTORS 256
+#define N_PAGES 256
+#define N_FILES_IN_SECTOR 8
+#define N_FILES_ON_PAGE 6
+#define N_INDEX_RECORDS 170
+#define N_RECORD_BYTES 3
+
+#define N_NAME 28
+
+#define N_INDEX_MARGIN 24
+#define N_MAX_DELETED 2
+
+/* This is a tradeoff between efficiency of memory space usage
+and frequency of defragmentation.
+With bigger value we're erasing and relocating less often,
+which extends the life of the flash memorym
+but we are wasting more space for deleted files.
+With the value of 2, even in the worst case, where each sector
+contains 2 deleted files we still have place for (8-2)*256=1536 files,
+which is exactly as much as we need.
+We can be 100% sure that we will not run out of space.
+We erase a sector 3 times less often than we delete files.
+We erase a sector when it has 3/8 of it's area deleted.
+With higher values it would still be statistically very unlikely
+but not impossible. To make it impossible I would have to do some
+checking of how much space is still free vs how much should be free
+for the remaining settings and react dynamically.
+But I prefer to stick with the simple spolution which is good enough.
+
+ETA: In the WORST case we will still miss 2 + 1 sectors
+(index + relocation place) = 24 settings.
+EXTREMELY unlikely,
+but I might still need to come up with something clever.
+Wait for it.
+
+ETAA: How about limit the number of pages to 250,
+which gives 1500 settings only?
+*/
+
+#define RECORD_OFFSET_ID 0
+#define RECORD_OFFSET_SECTOR 1
+#define RECORD_OFFSET_PAGE 2
+
+#define INDEX_OFFSET_RECORDS 2
+
+#define NEW_INDEX 0b10000000
+
+#define FILE_OFFSET_FLAG 0x000
+#define FILE_OFFSET_TYPE 0x001
+#define FILE_OFFSET_START 0x002
+#define FILE_OFFSET_PAGE 0x002
+#define FILE_OFFSET_ID 0x003
+#define FILE_OFFSET_ADSR 0x004
+#define FILE_OFFSET_ADSR_A 0x0
+#define FILE_OFFSET_ADSR_D 0x4
+#define FILE_OFFSET_ADSR_S 0x8
+#define FILE_OFFSET_ADSR_R 0xC
+#define FILE_OFFSET_NAME 0x014
+#define FILE_OFFSET_UNUSED 0x030
+#define FILE_OFFSET_WAVE 0x100
+#define FILE_OFFSET_NEXT 0x200
+
+#define PAGEID_SHIFT 4
+#define PAGEID_MASK 0b01110000
+#define SECTRID_SHIFT 0
+#define SECTRID_MASK 0b00000111
+
+#define FILE_FREE 0b11111111
+#define FILE_RESERVED 0b11111110
+#define FILE_INDEX_0 0b01010100
+#define FILE_INDEX_1 0b10101010
+#define FILE_NORMAL 0b00111110
+#define FILE_DELETED 0b00000000
+#define FILE_INVALID 0xff00
+
+#define RECORD_FLAGS 0b10001000
+#define RECORD_FREE 0b10001000
+#define RECORD_ACTIVE 0b00001000
+#define RECORD_DELETED 0b00000000
+
+#define PAGE_FLAGS 0b00111111
+#define SECTOR_FLAGS 0b11111111
+
+#define FILE_BITS 9
+#define FILEID_BITS 3
+#define SECTOR_BITS 8
+
+extern int16_t fs_page;
+extern uint8_t fs_page_flags;
+extern int16_t fs_page_sectors[N_FILES_ON_PAGE];
+extern int16_t fs_page_fileids[N_FILES_ON_PAGE];
+extern uint8_t fs_page_names[N_FILES_ON_PAGE][N_NAME+1];
+
+inline void fs_watchdog (void) LOWTEXT;
+
+// SPI flash handling
+inline uint8_t fs_spi_1b (const uint8_t data); // send & receive single byte
+void fs_spi( // execute single command
+ const uint8_t opcode,
+ const uint16_t address_bytes,
+ const uint16_t dummy_bytes,
+ const uint16_t data_bytes,
+ const uint32_t address,
+ uint8_t * const read_data,
+ const uint8_t * const write_data,
+ const uint8_t flag
+);
+
+// SPI flash commands
+inline void fs_spi_read2 (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+);
+inline void fs_spi_read1 (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+);
+inline void fs_spi_read (
+ const uint32_t address,
+ const uint16_t n,
+ uint8_t * const data
+);
+inline void fs_spi_erase_4k (const uint32_t address);
+inline void fs_spi_erase_32k (const uint32_t address);
+inline void fs_spi_erase_64k (const uint32_t address);
+inline void fs_spi_erase_chip (void);
+inline void fs_spi_program (
+ const uint32_t address,
+ const uint16_t n,
+ const uint8_t * const data
+);
+inline void fs_spi_write_enable (void);
+inline void fs_spi_write_disable (void);
+inline void fs_spi_protect_sector (uint32_t address);
+inline void fs_spi_unprotect_sector (const uint32_t address);
+inline uint8_t fs_spi_read_sector_protection (const uint32_t address);
+inline uint16_t fs_spi_read_status (void);
+inline void fs_spi_write_status_low (const uint8_t status);
+inline void fs_spi_write_status_high (const uint8_t status);
+inline void fs_spi_write_status (const uint16_t status);
+inline void fs_spi_reset (void);
+inline uint32_t fs_spi_read_id (void);
+
+inline void fs_wait_ready (const uint16_t timeout);
+
+// support for filesystem operations
+inline uint32_t fs_expand_address (
+ const uint8_t sector,
+ const uint8_t id,
+ const uint16_t offset
+);
+inline uint32_t fs_expand_record_address (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record
+);
+inline uint8_t fs_is_sector_free (const uint8_t sector);
+inline uint8_t fs_is_file_free (
+ const uint8_t sector,
+ const uint8_t id
+);
+uint16_t fs_get_file_type (
+ const uint8_t sector,
+ const uint8_t id
+);
+inline uint16_t fs_get_index_validation (const uint8_t sector);
+
+// filesystem indexing
+inline void fs_locate_index (void);
+inline void fs_scan_index (void);
+inline void fs_index_next_record (void);
+inline void fs_index_next_sector (void);
+inline void fs_index_next_file (void);
+
+// filesystem operations, low level
+uint8_t fs_create_file (
+ const uint8_t sector,
+ const uint8_t id,
+ const uint8_t type
+);
+uint8_t fs_delete_file (
+ const uint8_t sector,
+ const uint8_t id
+);
+uint8_t fs_duplicate_file (
+ const uint8_t src_sector,
+ const uint8_t src_id,
+ const uint8_t dst_sector,
+ const uint8_t dst_id
+);
+inline void fs_erase_sector (const uint8_t sector);
+void fs_format (void);
+uint8_t fs_read_record (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record,
+ uint8_t * const page,
+ uint8_t * const id,
+ uint8_t * const sector,
+ uint8_t * const fileid
+);
+void fs_write_record (
+ const uint8_t index,
+ const uint8_t block,
+ const uint8_t record,
+ const uint8_t page,
+ const uint8_t id,
+ const uint8_t sector,
+ const uint8_t fileid
+);
+void fs_delete_record (
+ uint8_t index,
+ uint8_t block,
+ uint8_t record
+);
+
+// filesystem operations, high level
+void fs_get_file_name(
+ const uint8_t sector,
+ const uint8_t id,
+ uint8_t * const name
+);
+void fs_load_page (const uint8_t new_page);
+void fs_store_voice (
+ const uint8_t id,
+ const uint8_t * const name,
+ const uint32_t A,
+ const uint32_t D,
+ const uint32_t S,
+ const uint32_t R,
+ const uint8_t * const wave
+);
+uint8_t fs_load_voice (
+ const uint8_t id,
+ uint32_t * const A,
+ uint32_t * const D,
+ uint32_t * const S,
+ uint32_t * const R,
+ uint8_t * const wave
+);
+void fs_optimise_sector (const uint8_t opt_sector);
+void fs_optimise_index (void);
+
+// general
+inline void setup_fs (void);
+inline void init_fs (void);
+void debug_file (
+ const uint8_t sector,
+ const uint8_t id
+);
+void debug_sector (const uint8_t sector);
--- /dev/null
+/* GUI */
+/*
+Copyright 2021, 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "klavirko-ui.h"
+#include "gui.h"
+#include "debug.h"
+#include "wave.h"
+#include "lcd.h"
+#include "main.h"
+#include "fs.h"
+#include "ctrl.h"
+
+volatile uint8_t button = 0;
+volatile uint8_t button_old = 0;
+volatile uint8_t button_new = 0;
+volatile uint16_t button_count = 0;
+volatile uint16_t button_hold_count = 0;
+volatile uint16_t button_y_count = 0;
+
+volatile uint8_t jog = 0;
+volatile uint8_t jog_old = 0;
+volatile uint8_t jog_new = 0;
+
+volatile uint16_t gui_event[N_GUI_EVENT];
+volatile uint8_t gui_event_r = 0;
+volatile uint8_t gui_event_w = 0;
+
+ uint8_t redraw_adsr = 0;
+ uint8_t redraw_wave = 0;
+ uint8_t wave_shape[N_SAMPLE];
+ uint8_t adsr_shape[N_SAMPLE];
+
+ uint8_t gui_state = GUI_INIT;
+ uint8_t gui_return_state = GUI_WAVE;
+ uint8_t gui_errors = 0;
+ uint8_t gui_accepted_errors = GUI_ERRF_ALL;
+
+ uint8_t gui_page=0;
+ uint8_t gui_name[N_NAME+1] = {[0 ... (N_NAME)] = '\0'};
+
+ uint8_t gui_name_cursor;
+ uint8_t gui_name_pos;
+ uint8_t gui_name_maxcursor;
+const uint8_t *gui_name_list;
+const uint8_t gui_list_ABC[N_ABC+1] = LIST_ABC;
+const uint8_t gui_list_abc[N_abc+1] = LIST_abc;
+const uint8_t gui_list_123[N_123+1] = LIST_123;
+ uint8_t gui_ignore_event = 0;
+
+ uint8_t text_tuning[GUI_BUTTONTEXT_TUNING_N] = GUI_BUTTONTEXT_TUNING;
+ uint8_t text_transpose[GUI_BUTTONTEXT_TRANSPOSE_N] = GUI_BUTTONTEXT_TRANSPOSE;
+ uint8_t text_midi_in[GUI_BUTTONTEXT_MIDI_IN_N] = GUI_BUTTONTEXT_MIDI_IN;
+ uint8_t text_midi_out[GUI_BUTTONTEXT_MIDI_OUT_N] = GUI_BUTTONTEXT_MIDI_OUT;
+ uint8_t text_select[GUI_TITLE_SELECT_N] = GUI_TITLE_SELECT;
+ uint8_t text_save[GUI_TITLE_SAVE_N] = GUI_TITLE_SAVE;
+
+/* event handling */
+
+inline void add_gui_event(const uint16_t event)
+{
+ if((gui_event_w + 1 == gui_event_r) || (gui_event_w + 1 == gui_event_r + N_GUI_EVENT)) // event buffer is full
+ return;
+ else
+ {
+ // add event, advance pointer
+ gui_event[gui_event_w] = event;
+ if (gui_event_w >= N_GUI_EVENT - 1)
+ gui_event_w = 0;
+ else
+ ++gui_event_w;
+ }
+}
+
+inline void reject_gui_events (void)
+{
+ gui_event_r = gui_event_w;
+}
+
+inline void gui_trigger_error (const uint8_t error)
+{
+ gui_errors |= (error & gui_accepted_errors);
+}
+
+inline void gui_ignore_error (const uint8_t error)
+{
+ gui_accepted_errors &= ~error;
+ gui_errors &= ~error;
+}
+
+/* handle changes */
+
+inline void gui_update_adsr (void)
+{
+ redraw_adsr = 1;
+}
+
+inline void gui_update_wave (void)
+{
+ redraw_wave = 1;
+}
+
+inline void gui_lock_wave (void)
+{
+ LED_V = 1;
+ lock_wave();
+}
+
+inline void gui_unlock_wave (void)
+{
+ unlock_wave();
+ update_wave();
+ LED_V = 0;
+}
+
+inline void gui_lock_adsr (void)
+{
+ LED_W = 1;
+ lock_adsr();
+}
+
+inline void gui_unlock_adsr (void)
+{
+ unlock_adsr();
+ update_adsr();
+ LED_W = 0;
+}
+
+inline void gui_switch_wave (void)
+{
+ if (wave_locked)
+ gui_unlock_wave();
+ else
+ gui_lock_wave();
+}
+
+inline void gui_switch_adsr (void)
+{
+ if (adsr_locked)
+ gui_unlock_adsr();
+ else
+ gui_lock_adsr();
+}
+
+/* handling inputs */
+
+inline void int_jog (void) // interrupt from rotary dial
+{
+ jog_old = jog_new;
+ jog_new = GET_JOG();
+
+ if(!(jog_new & 0x1)) //full position
+ {
+ if(jog_new != jog) //new position, not return
+ {
+ jog = jog_new;
+ add_gui_event(EVENT_JOG | ((jog_new - jog_old) & 0x3));
+ }
+ }
+}
+
+inline void int_button_abcdef(void) // interrupt from button ADC
+{
+ uint8_t adc;
+ uint8_t bits;
+ uint8_t press;
+ uint8_t release;
+
+ // get value
+ adc = ADCRH;
+
+ // decode to bits, 3 buttons state
+ if (adc <=BUTTON_THR_0)
+ bits = BUTTON_A | BUTTON_B | BUTTON_C;
+ else if (adc <= BUTTON_THR_1)
+ bits = BUTTON_B | BUTTON_C;
+ else if (adc <= BUTTON_THR_2)
+ bits = BUTTON_A | BUTTON_C;
+ else if (adc <= BUTTON_THR_3)
+ bits = BUTTON_C;
+ else if (adc <= BUTTON_THR_4)
+ bits = BUTTON_A | BUTTON_B;
+ else if (adc <= BUTTON_THR_5)
+ bits = BUTTON_B;
+ else if (adc <= BUTTON_THR_6)
+ bits = BUTTON_A;
+ else
+ bits = 0;
+
+ button_old = button_new;
+
+ if (ADS == BUTTON_ABC__ADS) // buttons ABC were read
+ {
+ ADS = BUTTON_DEF__ADS; // select DEF for next time
+ button_new = (button_new & (~BUTTON_ABC)) | bits; // update ABC state
+
+ // also check button X now
+ if (BUTTON_X__P)
+ button_new |= BUTTON_X;
+ else
+ button_new &= ~BUTTON_X;
+ }
+ else // buttond DEF were read
+ {
+ ADS = BUTTON_ABC__ADS; // select ABC for next time
+ button_new = (button_new & (~BUTTON_DEF)) | (bits<<3); // update DEF state
+
+ // also check button Y now: how many changes were counted?
+ if (button_y_count < 3)
+ button_new |= BUTTON_Y;
+ else
+ button_new &= ~BUTTON_Y;
+ button_y_count = 0;
+ }
+
+ // do button debouncing for pressing and releasing
+ if (button_new == button_old)
+ {
+ if (button_count < BUTTON_DEBOUNCE)
+ {
+ ++button_count;
+ if (button_count == BUTTON_DEBOUNCE)
+ {
+ button_hold_count = button_count;
+ press = button_new & (~button);
+ release = button & (~button_new);
+ button = button_new;
+ if (press)
+ add_gui_event(EVENT_PRESS | press);
+ if (release)
+ add_gui_event(EVENT_RELEASE | release);
+ }
+ }
+ }
+ else
+ button_count = 0;
+
+ // do button debouncing for long hold
+ if (button_hold_count < BUTTON_HOLD)
+ {
+ ++button_hold_count;
+ if (button_hold_count == BUTTON_HOLD)
+ {
+ if(button)
+ add_gui_event(EVENT_HOLD | button);
+ }
+ }
+}
+
+inline void int_button_y (void) // interrupt from button Y - square wave input
+{
+ ++button_y_count;
+}
+
+/* general setup */
+
+inline void setup_gui(void)
+{
+ PER0 |= //enable:
+ 0b10000000| //interval timer
+ 0b00100000; //ADC
+
+ /* * * SETUP LED V,W * * */
+
+ LED_V__PM = 0;
+ LED_V = 0;
+
+ LED_W = 0;
+ LED_W__PM = 0;
+
+ /* * * SETUP BUTTON Y * * */
+
+ BUTTON_Y__PM = 1;
+ BUTTON_Y__PU = 0;
+
+ BUTTON_Y__KRM = 1; //enable key int. detect
+ BUTTON_Y__MK = 0; //enable int.
+
+ /* * * SETUP SELECTOR * * */
+
+ JOG_A__PU = 0;
+ JOG_A__POM = 0;
+ JOG_A__PM = 1;
+
+ JOG_B__PU = 0;
+ JOG_B__PM = 1;
+
+ //enable both edges
+ JOG_A__EGP = 1;
+ JOG_A__EGN = 1;
+ JOG_B__EGP = 1;
+ JOG_B__EGN = 1;
+
+ //enable int.
+ JOG_A__MK = 0;
+ JOG_B__MK = 0;
+
+ //initial state
+ jog = jog_new = jog_old = GET_JOG();
+
+ /* * * SETUP INTERVAL TIMER * * */
+ // to use for ADC
+ OSMC = 0b00010000;
+ ITMC = 0x800e; //start, f = 15kHz / 15 = 1kHz;
+ // MK1h_bit.no2 = 0; //enable timer interrupt NOT NEEDED
+
+ /* * * SETUP BUTTON ADC * * */
+
+ //pins
+ BUTTON_ABC__PM = 1;
+ BUTTON_DEF__PM = 1;
+ LCD_CONTRAST__PM = 1;
+ ADPC = 0x05;
+
+ ADM0 = 0b00000000; //mode... 38us...
+ ADM1 = 0b10100011; //oneshot trigger is interval timer
+ ADM2 = 0b00000000; //ref: vdd vss, 10bit.
+ ADS = BUTTON_ABC__ADS; //select channel
+
+ ADM0 |= 0b00000001; //start ADCE
+ NOP_1us();
+ ADM0 |= 0b10000000; //start ADCS
+
+ MK1H_bit.no0 = 0; //enable AD int.
+}
+
+inline void init_gui(void)
+{
+ gui_state = GUI_INIT;
+ //TODO
+}
+
+/* state machine */
+
+// WAVE: waveform & envelope live display
+
+inline void gui_gotostate_wave (void)
+{
+ gui_state = GUI_WAVE;
+ gui_update_adsr();
+ gui_update_wave();
+ reject_gui_events();
+}
+
+inline void gui_event_wave (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_X)
+ {
+ gui_gotostate_options();
+ }
+ else if (event & BUTTON_Y)
+ {
+ gui_gotostate_select();
+ }
+ else if (event & (BUTTON_A | BUTTON_B))
+ {
+ gui_switch_wave();
+ }
+ else if (event & (BUTTON_C | BUTTON_D | BUTTON_E ))
+ {
+ gui_switch_adsr();
+ }
+ else if (event & BUTTON_F)
+ {
+ if(adsr_locked || wave_locked)
+ {
+ gui_unlock_wave();
+ gui_unlock_adsr();
+ }
+ else
+ {
+ gui_lock_wave();
+ gui_lock_adsr();
+ }
+ }
+ }
+ else if((event & EVENT_BITS) == EVENT_HOLD)
+ {
+ if (event & BUTTON_Y)
+ gui_gotostate_name(1);
+ }
+}
+
+inline void gui_exec_wave (void) // redraw if needed
+{
+ if (redraw_wave)
+ {
+ redraw_wave = 0;
+ draw_wave();
+ }
+ if (redraw_adsr)
+ {
+ redraw_adsr = 0;
+ draw_adsr();
+ }
+}
+
+// SELECT: voice settings selection
+
+inline void gui_gotostate_select (void)
+{
+ gui_state = GUI_SELECT;
+ draw_select();
+ reject_gui_events();
+}
+
+inline void gui_event_select (const uint16_t event)
+{
+ // uint8_t wave, adsr;
+ uint8_t id;
+
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_A | BUTTON_B | BUTTON_C | BUTTON_D | BUTTON_E | BUTTON_F))
+ {
+ if (event & BUTTON_A)
+ id = 0;
+ else if (event & BUTTON_B)
+ id = 1;
+ else if (event & BUTTON_C)
+ id = 2;
+ else if (event & BUTTON_D)
+ id = 3;
+ else if (event & BUTTON_E)
+ id = 4;
+ else
+ id = 5;
+
+ // adsr = adsr_locked;
+ // wave = wave_locked;
+
+ gui_lock_adsr();
+ gui_lock_wave();
+
+ if (fs_load_voice(
+ id,
+ &adsr_A,
+ &adsr_D,
+ &adsr_S,
+ &adsr_R,
+ sample)
+ ){
+ ctrl_update_wave();
+ ctrl_update_adsr();
+ gui_update_adsr();
+ gui_update_wave();
+ }
+ else
+ {
+ // if(!adsr)
+ gui_unlock_adsr();
+ // if(!wave)
+ gui_unlock_wave();
+ }
+ }
+ else if (event & BUTTON_X)
+ gui_gotostate_options();
+ else if (event & BUTTON_Y)
+ gui_gotostate_wave();
+ }
+ else if((event & EVENT_BITS) == EVENT_HOLD)
+ {
+ if (event & BUTTON_Y)
+ gui_gotostate_name(1);
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ ++gui_page;
+ else
+ --gui_page;
+ draw_select();
+ reject_gui_events();
+ }
+}
+
+// NAME: voice setting name input
+
+inline void gui_gotostate_name (const uint8_t new)
+{
+ if (new) // entering new name, not returning from cancelled location choice
+ {
+ gui_return_state = gui_state;
+ gui_name_pos = 0;
+ }
+ gui_state = GUI_NAME;
+
+ gui_name_list = gui_list_ABC;
+ gui_name_maxcursor = N_ABC-1;
+ gui_name_cursor = 0;
+ if (gui_name_pos < N_NAME)
+ {
+ gui_name[gui_name_pos] = (main_timer&512)?'_':' ';
+ gui_name[gui_name_pos+1] = '\0';
+ }
+ else
+ gui_name[gui_name_cursor] = '\0';
+ lcd_draw_name_menu (
+ GUI_TITLE_NAME,
+ gui_name_list,
+ gui_name_cursor,
+ gui_name,
+ GUI_BUTTONTEXT_DEL,
+ GUI_BUTTONTEXT_SPACE,
+ GUI_BUTTONTEXT_ABC,
+ GUI_BUTTONTEXT_abc,
+ GUI_BUTTONTEXT_123,
+ GUI_BUTTONTEXT_OK
+ );
+ reject_gui_events();
+ gui_ignore_event = new;
+}
+
+inline void gui_event_name (const uint16_t event)
+{
+ uint8_t oldcursor;
+
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_X)
+ {
+ if (gui_return_state == GUI_SELECT)
+ gui_gotostate_select();
+ else
+ gui_gotostate_wave();
+ }
+ else if (event & (BUTTON_A | BUTTON_B | BUTTON_Y))
+ {
+ if (event & BUTTON_A)
+ {
+ if(gui_name_pos >0)
+ --gui_name_pos;
+ }
+ else if (event & BUTTON_B)
+ {
+ if(gui_name_pos < N_NAME)
+ {
+ gui_name[gui_name_pos] = ' ';
+ ++gui_name_pos;
+ }
+ }
+ else if (event & BUTTON_Y)
+ {
+ if (gui_ignore_event)
+ gui_ignore_event = 0;
+ else if(gui_name_pos < N_NAME)
+ {
+ gui_name[gui_name_pos] = gui_name_list[gui_name_cursor];
+ ++gui_name_pos;
+ }
+ }
+ if (gui_name_pos < N_NAME)
+ {
+ gui_name[gui_name_pos] = (main_timer&512)?'_':' ';
+ gui_name[gui_name_pos+1] = '\0';
+ }
+ else
+ gui_name[gui_name_pos] = '\0';
+ lcd_update_button(-1,gui_name);
+ }
+ else if (event & ( BUTTON_C | BUTTON_D | BUTTON_E ))
+ {
+ if (event & BUTTON_C)
+ {
+ gui_name_list = gui_list_ABC;
+ gui_name_maxcursor = N_ABC-1;
+ }
+ else if (event & BUTTON_D)
+ {
+ gui_name_list = gui_list_abc;
+ gui_name_maxcursor = N_abc-1;
+ }
+ else if (event & BUTTON_E)
+ {
+ gui_name_list = gui_list_123;
+ gui_name_maxcursor = N_123-1;
+ }
+ lcd_draw_name_list(gui_name_list);
+ if (gui_name_cursor > gui_name_maxcursor)
+ {
+ lcd_erase_name_cursor(gui_name_cursor);
+ gui_name_cursor -= (gui_name_maxcursor + 1);
+ lcd_draw_name_cursor(gui_name_cursor);
+ }
+ }
+ else if (event & BUTTON_F)
+ {
+ if (gui_name_pos != 0)
+ {
+ gui_name[gui_name_pos] = '\0';
+ gui_gotostate_select_save();
+ }
+ }
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ oldcursor = gui_name_cursor;
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ {
+ if (gui_name_cursor < gui_name_maxcursor)
+ ++gui_name_cursor;
+ else
+ gui_name_cursor = 0;
+ }
+ else
+ {
+ if (gui_name_cursor != 0)
+ --gui_name_cursor;
+ else
+ gui_name_cursor = gui_name_maxcursor;
+ }
+ lcd_draw_name_cursor(gui_name_cursor);
+ lcd_erase_name_cursor(oldcursor);
+ }
+}
+
+inline void gui_exec_name (void) // do cursor blinking
+{
+ uint8_t cursor;
+
+ cursor = (main_timer & 512) ? '_' : ' ';
+ if ((gui_name_pos < N_NAME) && (gui_name[gui_name_pos] != cursor))
+ {
+ gui_name[gui_name_pos] = cursor;
+ lcd_update_button(-1, gui_name);
+ }
+}
+
+// SELECT_SAVE: voice setting save location selection
+
+inline void gui_gotostate_select_save (void)
+{
+ // gui_return_state = gui_state;
+ gui_state = GUI_SELECT_SAVE;
+ draw_select_save();
+ reject_gui_events();
+}
+
+inline void gui_event_select_save (const uint16_t event)
+{
+ uint8_t id;
+
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_A | BUTTON_B | BUTTON_C | BUTTON_D | BUTTON_E | BUTTON_F))
+ {
+ if (event & BUTTON_A)
+ id = 0;
+ else if (event & BUTTON_B)
+ id = 1;
+ else if (event & BUTTON_C)
+ id = 2;
+ else if (event & BUTTON_D)
+ id = 3;
+ else if (event & BUTTON_E)
+ id = 4;
+ else
+ id = 5;
+
+ fs_store_voice(
+ id,
+ gui_name,
+ adsr_A,
+ adsr_D,
+ adsr_S,
+ adsr_R,
+ sample
+ );
+
+ if (gui_return_state == GUI_SELECT)
+ gui_gotostate_select();
+ else
+ gui_gotostate_wave();
+ }
+ else if (event & BUTTON_X)
+ {
+ gui_gotostate_name(0);
+ }
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ ++gui_page;
+ else
+ --gui_page;
+ draw_select_save();
+ reject_gui_events();
+ }
+}
+
+// OPTIONS: menu with some settings
+
+inline void gui_gotostate_options (void)
+{
+ make_text_tuning ();
+ make_text_transpose();
+ make_text_midi_in ();
+ make_text_midi_out ();
+
+ gui_state = GUI_OPTIONS;
+ lcd_draw_menu (6,
+ GUI_TITLE_OPTIONS,"",
+ text_tuning,
+ text_transpose,
+ text_midi_in,
+ text_midi_out,
+ midi_pedal_en ? GUI_BUTTONTEXT_MIDI_PEDAL : GUI_BUTTONTEXT_MIDI_NOPEDAL,
+ GUI_BUTTONTEXT_RESET
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_options (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_X)
+ gui_gotostate_wave();
+ else if (event & BUTTON_Y)
+ gui_gotostate_select();
+ else if (event & BUTTON_A)
+ gui_gotostate_tuning();
+ else if (event & BUTTON_B)
+ gui_gotostate_transpose();
+ else if (event & BUTTON_C)
+ gui_gotostate_midi_id();
+ else if (event & BUTTON_D)
+ gui_gotostate_midi_id_out();
+ else if (event & BUTTON_E)
+ {
+ if (midi_pedal_en)
+ {
+ midi_pedal_en = 0;
+ lcd_update_button(4, GUI_BUTTONTEXT_MIDI_NOPEDAL);
+ }
+ else
+ {
+ midi_pedal_en = 1;
+ lcd_update_button(4, GUI_BUTTONTEXT_MIDI_PEDAL);
+ }
+ ctrl_update_midi();
+ }
+ else if (event & BUTTON_F)
+ gui_gotostate_total_reset();
+ }
+}
+
+// TUNING: change tuning of instrument
+
+inline void gui_gotostate_tuning (void)
+{
+ make_text_tuning();
+
+ gui_state = GUI_TUNING;
+ lcd_draw_menu (6,
+ GUI_TITLE_TUNING,"",
+ text_tuning, "", "", "", "", ""
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_tuning (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_X | BUTTON_Y | BUTTON_A))
+ gui_gotostate_options();
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ {
+ set_tuning(tuning + 1);
+ }
+ else
+ {
+ set_tuning(tuning - 1);
+ }
+
+ make_text_tuning();
+ lcd_update_button(0, text_tuning);
+ }
+}
+
+// TRANSPOSE: shift by -6 to 6 semitones
+
+inline void gui_gotostate_transpose (void)
+{
+ make_text_transpose();
+
+ gui_state = GUI_TRANSPOSE;
+ lcd_draw_menu (6,
+ GUI_TITLE_TRANSPOSE,"",
+ "",text_transpose, "", "", "", ""
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_transpose (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_X | BUTTON_Y | BUTTON_B))
+ gui_gotostate_options();
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ {
+ if (transp<6)
+ set_transp(transp + 1);
+ }
+ else
+ {
+ if (transp>-6)
+ set_transp(transp - 1);
+ }
+
+ make_text_transpose();
+ lcd_update_button(1, text_transpose);
+ }
+}
+
+// MIDI_ID: choose MIDI channel ID for input
+
+inline void gui_gotostate_midi_id (void)
+{
+ make_text_midi_in();
+
+ gui_state = GUI_MIDI_ID;
+ lcd_draw_menu (6,
+ GUI_TITLE_MIDI_ID,"",
+ "","",text_midi_in, "", "", ""
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_midi_id (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_X | BUTTON_Y | BUTTON_C))
+ gui_gotostate_options();
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ {
+ if (midi_id < N_MIDI_ID)
+ ++midi_id;
+ else
+ midi_id = 0;
+ }
+ else
+ {
+ if (midi_id != 0)
+ --midi_id;
+ else
+ midi_id = N_MIDI_ID;
+ }
+
+ ctrl_update_midi();
+ make_text_midi_in();
+ lcd_update_button(2, text_midi_in);
+ }
+}
+
+// MIDI_ID_OUT: choose MIDI channel ID for output
+
+inline void gui_gotostate_midi_id_out (void)
+{
+ make_text_midi_out();
+
+ gui_state = GUI_MIDI_ID_OUT;
+ lcd_draw_menu (6,
+ GUI_TITLE_MIDI_ID_OUT,"",
+ "","","",text_midi_out, "", ""
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_midi_id_out (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & (BUTTON_X | BUTTON_Y | BUTTON_D))
+ gui_gotostate_options();
+ }
+ else if((event & EVENT_BITS) == EVENT_JOG)
+ {
+ if ((event & ~EVENT_BITS) == JOG_PLUS)
+ {
+ if (midi_id_out < N_MIDI_ID-1)
+ ++midi_id_out;
+ else
+ midi_id_out = 0;
+ }
+ else
+ {
+ if (midi_id_out != 0)
+ --midi_id_out;
+ else
+ midi_id_out = N_MIDI_ID-1;
+ }
+
+ ctrl_update_midi();
+ make_text_midi_out();
+ lcd_update_button(3, text_midi_out);
+ }
+}
+
+// ERR_AIX: error from analog input expander
+
+inline void gui_gotostate_err_aix (void)
+{
+ gui_state = GUI_ERR_AIX;
+ lcd_draw_menu(1,
+ GUI_TITLE_ERR_AIX,"",
+ "","","","","",GUI_BUTTONTEXT_IGNORE
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_err_aix (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_F)
+ {
+ gui_ignore_error(GUI_ERRF_AIX);
+ gui_gotostate_wave();
+ }
+ }
+}
+
+// ERR_CTRL: error from communication with main controller
+
+inline void gui_gotostate_err_ctrl (void)
+{
+ gui_state = GUI_ERR_CTRL;
+ lcd_draw_menu(1,
+ GUI_TITLE_ERR_CTRL,"",
+ "","","","","",GUI_BUTTONTEXT_IGNORE
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_err_ctrl (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_F)
+ {
+ gui_ignore_error(GUI_ERRF_CTRL);
+ gui_gotostate_wave();
+ }
+ }
+}
+
+// ERR_FS: error from filesystem
+
+inline void gui_gotostate_err_fs (void)
+{
+ gui_state = GUI_ERR_FS;
+ lcd_draw_menu(3,
+ GUI_TITLE_ERR_FS,"",
+ "","","",
+ GUI_BUTTONTEXT_FORMAT,
+ GUI_BUTTONTEXT_RECOVER,
+ GUI_BUTTONTEXT_IGNORE
+ );
+ reject_gui_events();
+}
+
+inline void gui_event_err_fs (const uint16_t event)
+{
+ if((event & EVENT_BITS) == EVENT_RELEASE)
+ {
+ if (event & BUTTON_D)
+ {
+ gui_gotostate_total_reset();
+ }
+ else if (event & BUTTON_E)
+ {
+ // TODO: RECOVER
+ }
+ else if (event & BUTTON_F)
+ {
+ gui_ignore_error(GUI_ERRF_FS);
+ gui_gotostate_wave();
+ }
+ }
+}
+
+// TOTAL_RESET: reformat flash and restart
+
+inline void gui_gotostate_total_reset (void)
+{
+ gui_state = GUI_TOTAL_RESET;
+ lcd_draw_menu(0,
+ GUI_TITLE_RESET,"",
+ "","","","","",""
+ );
+ fs_format();
+ RESET_UI();
+}
+
+// Handle the actual GUI state machine
+void handle_gui(void)
+{
+ uint16_t event;
+
+ if (gui_event_r != gui_event_w) // event received
+ {
+ // get event, advance pointer
+ event = gui_event[gui_event_r];
+ if(gui_event_r >= N_GUI_EVENT - 1)
+ gui_event_r = 0;
+ else
+ ++gui_event_r;
+
+ // execute appropriate event handler for current state
+ switch (gui_state)
+ {
+ case GUI_WAVE:
+ gui_event_wave(event);
+ break;
+ case GUI_SELECT:
+ gui_event_select(event);
+ break;
+ case GUI_NAME:
+ gui_event_name(event);
+ break;
+ case GUI_SELECT_SAVE:
+ gui_event_select_save(event);
+ break;
+ case GUI_OPTIONS:
+ gui_event_options(event);
+ break;
+ case GUI_TUNING:
+ gui_event_tuning(event);
+ break;
+ case GUI_TRANSPOSE:
+ gui_event_transpose(event);
+ break;
+ case GUI_MIDI_ID:
+ gui_event_midi_id(event);
+ break;
+ case GUI_MIDI_ID_OUT:
+ gui_event_midi_id_out(event);
+ break;
+ case GUI_ERR_AIX:
+ gui_event_err_aix(event);
+ break;
+ case GUI_ERR_CTRL:
+ gui_event_err_ctrl(event);
+ break;
+ case GUI_ERR_FS:
+ gui_event_err_fs(event);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // execute current state handler if available
+ switch (gui_state)
+ {
+ case GUI_WAVE:
+ gui_exec_wave();
+ break;
+ case GUI_NAME:
+ gui_exec_name();
+ break;
+ case GUI_SELECT:
+ case GUI_SELECT_SAVE:
+ case GUI_OPTIONS:
+ case GUI_TUNING:
+ case GUI_TRANSPOSE:
+ case GUI_MIDI_ID:
+ case GUI_MIDI_ID_OUT:
+ case GUI_ERR_AIX:
+ case GUI_ERR_CTRL:
+ case GUI_ERR_FS:
+ break;
+ case GUI_INIT:
+ default:
+ gui_gotostate_wave();
+ break;
+ }
+
+ // error detected? goto error screen
+ if (gui_errors && !(gui_state & GUI_ERROR))
+ {
+ if (gui_errors & GUI_ERRF_FS)
+ gui_gotostate_err_fs();
+ else if (gui_errors & GUI_ERRF_CTRL)
+ gui_gotostate_err_ctrl();
+ else if (gui_errors & GUI_ERRF_AIX)
+ gui_gotostate_err_aix();
+ }
+}
+
+/* drawing of some screens */
+
+void draw_wave (void) // waveform display
+{
+ uint16_t i;
+ uint16_t x;
+
+ // convert sample to drawable shape
+ for(i = 0; i< N_SAMPLE; ++i)
+ {
+ x = (uint16_t)(sample[i]+128) * 229;
+ wave_shape[i] = x>>9;
+ }
+
+ lcd_draw_wave(wave_shape);
+}
+
+void draw_adsr (void) // envelope display
+{
+ uint16_t i;
+ uint32_t s;
+ uint32_t rd;
+ uint32_t x = 0;
+ uint32_t x0 = 0;
+ uint8_t a = 1;
+ uint8_t d = 0;
+
+ // TODO: make magic numbers to meaningful #defines!
+
+ // convert envelope to drawable shape
+
+ s = adsr_S >> 7;
+ s *= 115;
+ s >>= 8;
+
+ rd = (adsr_R > adsr_D) ? adsr_R : adsr_D;
+
+ for(i = 0; i < (N_SAMPLE>>1); ++i) // when key pressed
+ {
+ x0 = x;
+
+ if (a) // attack phase
+ {
+ x += adsr_A;
+ if ((x >= 0x00e58000) || ( x < x0)) // reached top, goto D
+ {
+ x = 0x00e58000;
+ a = 0;
+ d = 1;
+ }
+ }
+ else if (d) // decay phase
+ {
+ x -= adsr_D;
+ if ((x <= s) || (x > x0)) // reached threshold, goto S
+ {
+ x = s;
+ d = 0;
+ }
+ }
+
+ adsr_shape[i] = x >> 17;
+ }
+
+ d = 1;
+
+ for(i = (N_SAMPLE>>1); i < N_SAMPLE; ++i) // when key released
+ {
+ x0 = x;
+
+ if (d) // release decay phase above threshold
+ {
+ x -= rd;
+ if ((x <= s) || (x > x0)) // threshold reached, go below
+ {
+ x = s;
+ d = 0;
+ }
+ }
+ else if (x) // release decay phase below threshold
+ {
+ x -= adsr_R;
+ if (x > x0) // bottom reached, stop
+ x = 0;
+ }
+
+ adsr_shape[i] = x >> 17;
+ }
+
+ lcd_draw_adsr(adsr_shape);
+}
+
+void draw_select (void) // voice settings selection
+{
+ fs_load_page(gui_page);
+ make_text_select();
+
+ lcd_draw_menu(6,
+ text_select,
+ "",
+ fs_page_names[0],
+ fs_page_names[1],
+ fs_page_names[2],
+ fs_page_names[3],
+ fs_page_names[4],
+ fs_page_names[5]
+ );
+}
+
+void draw_select_save (void) // voice setting save location selection
+{
+ fs_load_page(gui_page);
+ make_text_save();
+
+ lcd_draw_menu(7,
+ text_save,
+ gui_name,
+ fs_page_names[0],
+ fs_page_names[1],
+ fs_page_names[2],
+ fs_page_names[3],
+ fs_page_names[4],
+ fs_page_names[5]
+ );
+}
+
+/* dynamic menu texts */
+
+inline void make_text_tuning (void)
+{
+ uint8_t x = GUI_BUTTONTEXT_TUNING_INSERT;
+ x += make_dec_string(text_tuning+GUI_BUTTONTEXT_TUNING_INSERT, tuning, 2, 4);
+ text_tuning[x ]=text_tuning[x-1];
+ text_tuning[(x++)-1]='.';
+ text_tuning[x++]='H';
+ text_tuning[x++]='z';
+ text_tuning[x ]='\0';
+}
+
+inline void make_text_transpose (void)
+{
+ uint8_t x = GUI_BUTTONTEXT_TRANSPOSE_INSERT;
+ uint8_t abs;
+
+ if (transp < 0)
+ {
+ abs = 0-transp;
+ text_transpose[x]='-';
+ }
+ else
+ {
+ abs = transp;
+ if (transp>0)
+ text_transpose[x]='+';
+ else
+ text_transpose[x]=' ';
+ }
+ ++x;
+ x += make_dec_string(text_transpose+x, abs, 1, 2);
+ text_transpose[x]='\0';
+}
+
+inline void make_text_midi_in (void)
+{
+ uint8_t x = GUI_BUTTONTEXT_MIDI_IN_INSERT;
+ if (midi_id < N_MIDI_ID)
+ {
+ x += make_dec_string(text_midi_in+GUI_BUTTONTEXT_MIDI_IN_INSERT, midi_id+1, 1, 2);
+ text_midi_in[x]='\0';
+ }
+ else
+ {
+ text_midi_in[x++]='A';
+ text_midi_in[x++]='L';
+ text_midi_in[x++]='L';
+ text_midi_in[x ]='\0';
+ }
+}
+
+inline void make_text_midi_out (void)
+{
+ uint8_t x = GUI_BUTTONTEXT_MIDI_OUT_INSERT;
+ x += make_dec_string(text_midi_out+GUI_BUTTONTEXT_MIDI_OUT_INSERT, midi_id_out+1, 1, 2);
+ text_midi_out[x]='\0';
+}
+
+inline void make_text_select (void)
+{
+ uint8_t x = GUI_TITLE_SELECT_INSERT;
+ x += make_dec_string(text_select+GUI_TITLE_SELECT_INSERT, fs_page+1, 1, 3);
+ text_select[x++]=')';
+ text_select[x ]='\0';
+}
+
+inline void make_text_save (void)
+{
+ uint8_t x = GUI_TITLE_SAVE_INSERT;
+ x += make_dec_string(text_save+GUI_TITLE_SAVE_INSERT, fs_page+1, 1, 3);
+ text_save[x++]=')';
+ text_save[x ]='\0';
+}
--- /dev/null
+/* GUI */
+/* Encoding of this file is ISO 8859-2 */
+/*
+Copyright 2021, 2022 Balthasar Szczepañski
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+
+#define GET_JOG() ((JOG_A ? 0x1 : 0x0) ^ (JOG_B ? 0x3 : 0x0))
+
+#define BUTTON_DEBOUNCE 4
+#define BUTTON_HOLD 680
+
+#define BUTTON_A 0b00000001
+#define BUTTON_B 0b00000010
+#define BUTTON_C 0b00000100
+#define BUTTON_D 0b00001000
+#define BUTTON_E 0b00010000
+#define BUTTON_F 0b00100000
+#define BUTTON_X 0b01000000
+#define BUTTON_Y 0b10000000
+
+#define BUTTON_ABC (BUTTON_A | BUTTON_B | BUTTON_C)
+#define BUTTON_DEF (BUTTON_D | BUTTON_E | BUTTON_F)
+#define BUTTON_ABCDEF (BUTTON_ABC | BUTTON_DEF)
+
+#define BUTTON_THR_0 58
+#define BUTTON_THR_1 66
+#define BUTTON_THR_2 76
+#define BUTTON_THR_3 91
+#define BUTTON_THR_4 114
+#define BUTTON_THR_5 147
+#define BUTTON_THR_6 208
+
+#define JOG_PLUS 1
+#define JOG_MINUS 3
+
+#define N_GUI_EVENT 16
+
+#define EVENT_BITS 0xE000
+#define EVENT_PRESS 0x8000
+#define EVENT_RELEASE 0x4000
+#define EVENT_HOLD 0xC000
+#define EVENT_JOG 0x2000
+
+#define GUI_INIT 0x00
+#define GUI_WAVE 0x01
+#define GUI_SELECT 0x02
+#define GUI_SELECT_SAVE 0x03
+#define GUI_NAME 0x04
+#define GUI_OPTIONS 0x10
+#define GUI_TUNING 0x11
+#define GUI_TRANSPOSE 0x12
+#define GUI_MIDI_ID 0x13
+#define GUI_MIDI_ID_OUT 0x14
+
+#define GUI_ERROR 0x80
+#define GUI_ERR_AIX 0x81
+#define GUI_ERR_CTRL 0x82
+#define GUI_ERR_FS 0x83
+#define GUI_TOTAL_RESET 0xff
+
+#define GUI_ERRF_AIX 0b00000001
+#define GUI_ERRF_CTRL 0b00000010
+#define GUI_ERRF_FS 0b00000100
+
+#define GUI_ERRF_ALL (GUI_ERRF_AIX | GUI_ERRF_CTRL | GUI_ERRF_FS)
+
+#define LIST_ABC "A¡BCÆDEÊFGHIJKL£MNÑOÓPQRS¦TUVWXYZ¬¯"
+#define LIST_abc "a±bcædeêfghijkl³mnñoópqrs¶tuvwxyz¼¿"
+#define LIST_123 "0123456789.,!?:;+-*/=\\^<>()[]{}#$%&'\"`~_|@"
+
+#define N_ABC 35
+#define N_abc 35
+#define N_123 42
+
+#define GUI_TITLE_NAME "Save as:"
+#define GUI_TITLE_OPTIONS "Options:"
+#define GUI_TITLE_TUNING "Tuning:"
+#define GUI_TITLE_TRANSPOSE "Transpose:"
+#define GUI_TITLE_MIDI_ID "MIDI in ID:"
+#define GUI_TITLE_MIDI_ID_OUT "MIDI out ID:"
+#define GUI_TITLE_ERR_AIX "AIX communication fail!"
+#define GUI_TITLE_ERR_CTRL "CTRL communication fail!"
+#define GUI_TITLE_ERR_FS "File system unformatted or damaged!"
+#define GUI_TITLE_RESET "TERAS BENDZIE INNY $WIAT"
+
+#define GUI_BUTTONTEXT_DEL " <xx"
+#define GUI_BUTTONTEXT_SPACE ""
+#define GUI_BUTTONTEXT_ABC " ABC"
+#define GUI_BUTTONTEXT_abc " abc"
+#define GUI_BUTTONTEXT_123 " 123!?"
+#define GUI_BUTTONTEXT_OK " OK."
+#define GUI_BUTTONTEXT_MIDI_PEDAL "MIDI pedal allowed"
+#define GUI_BUTTONTEXT_MIDI_NOPEDAL "MIDI pedal illegal"
+#define GUI_BUTTONTEXT_RESET " TOTAL RESET"
+#define GUI_BUTTONTEXT_IGNORE "ignore and resume"
+#define GUI_BUTTONTEXT_RECOVER "recover(TODO)"
+#define GUI_BUTTONTEXT_FORMAT "format"
+
+#define GUI_BUTTONTEXT_TUNING "tuning "
+#define GUI_BUTTONTEXT_TUNING_N 15
+#define GUI_BUTTONTEXT_TUNING_INSERT 7
+
+#define GUI_BUTTONTEXT_TRANSPOSE "transp. +x "
+#define GUI_BUTTONTEXT_TRANSPOSE_N 13
+#define GUI_BUTTONTEXT_TRANSPOSE_INSERT 9
+
+#define GUI_BUTTONTEXT_MIDI_IN "MIDI inID= "
+#define GUI_BUTTONTEXT_MIDI_IN_N 14
+#define GUI_BUTTONTEXT_MIDI_IN_INSERT 10
+
+#define GUI_BUTTONTEXT_MIDI_OUT "MIDIoutID= "
+#define GUI_BUTTONTEXT_MIDI_OUT_N 13
+#define GUI_BUTTONTEXT_MIDI_OUT_INSERT 10
+
+#define GUI_TITLE_SELECT "Select voice: (page "
+#define GUI_TITLE_SELECT_N 29
+#define GUI_TITLE_SELECT_INSERT 24
+
+#define GUI_TITLE_SAVE "Save where(page "
+#define GUI_TITLE_SAVE_N 21
+#define GUI_TITLE_SAVE_INSERT 16
+
+// event handling
+
+inline void add_gui_event(const uint16_t event);
+inline void reject_gui_events (void);
+inline void gui_trigger_error (const uint8_t error);
+inline void gui_ignore_error (const uint8_t error);
+
+// handle changes
+
+inline void gui_update_adsr (void);
+inline void gui_update_wave (void);
+inline void gui_lock_wave (void);
+inline void gui_unlock_wave (void);
+inline void gui_lock_adsr (void);
+inline void gui_unlock_adsr (void);
+inline void gui_switch_wave (void);
+inline void gui_switch_adsr (void);
+
+// handling inputs
+
+inline void int_jog (void) LOWTEXT_INT;
+inline void int_button_abcdef (void) LOWTEXT;
+inline void int_button_y (void) LOWTEXT_INT;
+
+// general setup
+
+inline void setup_gui(void);
+inline void init_gui(void);
+
+// state machine
+
+inline void gui_gotostate_wave (void);
+inline void gui_gotostate_select (void);
+inline void gui_gotostate_name (const uint8_t new);
+inline void gui_gotostate_select_save (void);
+inline void gui_gotostate_options (void);
+inline void gui_gotostate_tuning (void);
+inline void gui_gotostate_transpose (void);
+inline void gui_gotostate_midi_id (void);
+inline void gui_gotostate_midi_id_out (void);
+inline void gui_gotostate_err_aix (void);
+inline void gui_gotostate_err_ctrl (void);
+inline void gui_gotostate_err_fs (void);
+inline void gui_gotostate_total_reset (void);
+
+inline void gui_event_wave (const uint16_t event);
+inline void gui_event_select (const uint16_t event);
+inline void gui_event_name (const uint16_t event);
+inline void gui_event_select_save (const uint16_t event);
+inline void gui_event_options (const uint16_t event);
+inline void gui_event_tuning (const uint16_t event);
+inline void gui_event_transp (const uint16_t event);
+inline void gui_event_midi_id (const uint16_t event);
+inline void gui_event_midi_id_out (const uint16_t event);
+inline void gui_event_err_aix (const uint16_t event);
+inline void gui_event_err_ctrl (const uint16_t event);
+inline void gui_event_err_fs (const uint16_t event);
+
+inline void gui_exec_wave (void);
+inline void gui_exec_name (void);
+
+ void handle_gui(void);
+
+// drawing of some screens
+
+ void draw_wave (void);
+ void draw_adsr (void);
+ void draw_select (void);
+ void draw_select_save (void);
+
+// dynamic menu texts
+
+inline void make_text_tuning (void);
+inline void make_text_transpose (void);
+inline void make_text_midi_in (void);
+inline void make_text_midi_out (void);
+inline void make_text_select (void);
+inline void make_text_save (void);
--- /dev/null
+/* convert font: PNG to H */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "IL/il.h" // Dev Image Library
+
+int cleanup(const char *t,int m,int e);
+int main(int argc, char *argv[]);
+
+ILuint inpix;
+
+int main(int argc, char *argv[])
+{
+ ILubyte *data;
+ ILint Y;
+ uint16_t h, x, y, c, i;
+ uint8_t v;
+
+ if (argc<3)
+ return cleanup("img2fnt name file",0,1);
+
+ ilInit();
+
+ ilEnable(IL_ORIGIN_SET);
+ ilEnable(IL_FILE_OVERWRITE);
+
+ ilGenImages(1,&inpix);
+ ilBindImage(inpix);
+
+ if(!ilLoadImage(argv[2]))
+ return cleanup("Load fail.",1,1);
+
+ if(ilGetInteger(IL_IMAGE_FORMAT)!=IL_COLOUR_INDEX)
+ return cleanup("Not indexed.",1,1);
+
+ if(ilGetInteger(IL_IMAGE_WIDTH)!=128)
+ return cleanup("Incorrect width.",1,1);
+
+ Y = ilGetInteger(IL_IMAGE_HEIGHT);
+ if (Y == 256)
+ h = 2;
+ else if (Y == 128)
+ h = 1;
+ else
+ return cleanup("Incorrect height.",1,1);
+
+ data=ilGetData();
+
+ fprintf(stdout,"//autogenerated from %s by img2font.c\n", argv[2]);
+ fprintf(stdout,"#define %s { \\\n", argv[1]);
+
+ for (c=0; c<256; ++c)
+ {
+ fprintf(stdout, "\t/* %02" PRIX16 " */", c);
+ for (x=0; x<8; ++x)
+ {
+ for (i=0; i<h; ++i)
+ {
+ fputs(" ",stdout);
+ v = 0;
+ for (y=0; y<8; ++y)
+ {
+ if (data[((15-(c/16))*8*h+(h-i-1)*8+7-y)*128+(c%16)*8+x])
+ v |= 1 << y;
+ }
+ fprintf(stdout, "0x%02" PRIx16 ",", v);
+ }
+ }
+ fputs(" \\\n",stdout);
+ }
+
+ fputs("}\n", stdout);
+
+ return cleanup("Ok.",1,0);
+
+}
+int cleanup(const char *t, int m,int e)
+{
+ if(t[0] != 0)
+ fprintf(stderr, "%s\n", t);
+ switch (m)
+ {
+ // case 2:
+ // fclose(outfile);
+ case 1:
+ ilDeleteImages(1,&inpix);
+ case 0:
+ default:
+ return e;
+ }
+}
--- /dev/null
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interrupt_handlers.h"
+#include "aix.h"
+#include "fs.h"
+#include "gui.h"
+#include "main.h"
+#include "ctrl.h"
+
+void FALLBACK_INT (void) { }
+
+
+// INT_AD (0x34)
+void INT_AD (void)
+{
+ // because this int. arrives every 1ms,
+ // use it as a global time source
+ int_button_abcdef();
+ int_main_timer();
+ aix_watchdog();
+ ctrl_watchdog();
+ fs_watchdog();
+}
--- /dev/null
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef INTERRUPT_HANDLERS_H
+#define INTERRUPT_HANDLERS_H
+
+#include "klavirko-ui.h"
+
+void FALLBACK_INT (void) LOWTEXT_INT;
+
+
+// INT_AD (0x34)
+void INT_AD (void) LOWTEXT_INT;
+
+// HWV
+// PowerON_Reset (0x0)
+void PowerON_Reset (void) __attribute__ ((interrupt));
+#endif
--- /dev/null
+/*
+The poor replacement for the iodefine.h and iodefine_ext.h files autogenerated by e2studio.
+
+I only provided replacements for things that I actually use in project.
+(i did not want to waste too much effort on this pointless task)
+So the definition will be incomplete.
+Extend if needed, based on the hardware reference document.
+
+You will notice much similarity to the replaced thing.
+That's because these things must have such values to work correctly.
+Which makes the replacement kind of a pointless work as in the end
+almost the same thing comes out. But now it is mine.
+So, I believe this should not even be copyrightable,
+In case it is then consider it copyrighted and released under the same
+license as the other files:
+*/
+/*
+Copyright 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* R5F104JG microcontroller */
+
+#include <stdint.h>
+
+#define DI() asm("di")
+#define EI() asm("ei")
+#define NOP() asm("nop")
+
+// I leave all names as in original file to preserve compatibility!
+// (it's a _replacement_ after all)
+// but redefined to stdint type for clarity
+
+// structure for sigle bit access.
+
+typedef struct {
+ uint8_t no0 :1;
+ uint8_t no1 :1;
+ uint8_t no2 :1;
+ uint8_t no3 :1;
+ uint8_t no4 :1;
+ uint8_t no5 :1;
+ uint8_t no6 :1;
+ uint8_t no7 :1;
+} __BITS8;
+
+typedef struct {
+ uint16_t no0 :1;
+ uint16_t no1 :1;
+ uint16_t no2 :1;
+ uint16_t no3 :1;
+ uint16_t no4 :1;
+ uint16_t no5 :1;
+ uint16_t no6 :1;
+ uint16_t no7 :1;
+ uint16_t no8 :1;
+ uint16_t no9 :1;
+ uint16_t no10 :1;
+ uint16_t no11 :1;
+ uint16_t no12 :1;
+ uint16_t no13 :1;
+ uint16_t no14 :1;
+ uint16_t no15 :1;
+} __BITS16;
+
+// Didn't bother with the union thing; not needed at all.
+
+#define ADM2 (*(volatile uint8_t *) 0xF0010)
+#define ADM2_bit (*(volatile __BITS8 *) 0xF0010)
+
+#define PU0 (*(volatile uint8_t *) 0xF0030)
+#define PU0_bit (*(volatile __BITS8 *) 0xF0030)
+
+#define PU1 (*(volatile uint8_t *) 0xF0031)
+#define PU1_bit (*(volatile __BITS8 *) 0xF0031)
+
+#define PU3 (*(volatile uint8_t *) 0xF0033)
+#define PU3_bit (*(volatile __BITS8 *) 0xF0033)
+
+#define PU5 (*(volatile uint8_t *) 0xF0035)
+#define PU5_bit (*(volatile __BITS8 *) 0xF0035)
+
+#define PU7 (*(volatile uint8_t *) 0xF0037)
+#define PU7_bit (*(volatile __BITS8 *) 0xF0037)
+
+#define PU14 (*(volatile uint8_t *) 0xF003E)
+#define PU14_bit (*(volatile __BITS8 *) 0xF003E)
+
+#define PIM0 (*(volatile uint8_t *) 0xF0040)
+#define PIM0_bit (*(volatile __BITS8 *) 0xF0040)
+
+#define PIM1 (*(volatile uint8_t *) 0xF0041)
+#define PIM1_bit (*(volatile __BITS8 *) 0xF0041)
+
+#define PIM3 (*(volatile uint8_t *) 0xF0043)
+#define PIM3_bit (*(volatile __BITS8 *) 0xF0043)
+
+#define POM0 (*(volatile uint8_t *) 0xF0050)
+#define POM0_bit (*(volatile __BITS8 *) 0xF0050)
+
+#define POM1 (*(volatile uint8_t *) 0xF0051)
+#define POM1_bit (*(volatile __BITS8 *) 0xF0051)
+
+#define POM3 (*(volatile uint8_t *) 0xF0053)
+#define POM3_bit (*(volatile __BITS8 *) 0xF0053)
+
+#define POM5 (*(volatile uint8_t *) 0xF0055)
+#define POM5_bit (*(volatile __BITS8 *) 0xF0055)
+
+#define POM7 (*(volatile uint8_t *) 0xF0057)
+#define POM7_bit (*(volatile __BITS8 *) 0xF0057)
+
+#define PMC0 (*(volatile uint8_t *) 0xF0060)
+#define PMC0_bit (*(volatile __BITS8 *) 0xF0060)
+
+#define PMC1 (*(volatile uint8_t *) 0xF0061)
+#define PMC1_bit (*(volatile __BITS8 *) 0xF0061)
+
+#define PMC12 (*(volatile uint8_t *) 0xF006C)
+#define PMC12_bit (*(volatile __BITS8 *) 0xF006C)
+
+#define PMC14 (*(volatile uint8_t *) 0xF006E)
+#define PMC14_bit (*(volatile __BITS8 *) 0xF006E)
+
+#define ADPC (*(volatile uint8_t *) 0xF0076)
+
+#define PER1 (*(volatile uint8_t *) 0xF007A)
+#define PER1_bit (*(volatile __BITS8 *) 0xF007A)
+
+#define HOCODIV (*(volatile uint8_t *) 0xF00A8)
+
+#define PER0 (*(volatile uint8_t *) 0xF00F0)
+#define PER0_bit (*(volatile __BITS8 *) 0xF00F0)
+
+#define OSMC (*(volatile uint8_t *) 0xF00F3)
+
+#define SSR00 (*(volatile uint16_t *) 0xF0100)
+
+#define SSR01 (*(volatile uint16_t *) 0xF0102)
+
+#define SSR02 (*(volatile uint16_t *) 0xF0104)
+
+#define SSR03 (*(volatile uint16_t *) 0xF0106)
+
+#define SIR01 (*(volatile uint16_t *) 0xF010A)
+
+#define SIR03 (*(volatile uint16_t *) 0xF010E)
+
+#define SMR00 (*(volatile uint16_t *) 0xF0110)
+
+#define SMR01 (*(volatile uint16_t *) 0xF0112)
+
+#define SMR02 (*(volatile uint16_t *) 0xF0114)
+
+#define SMR03 (*(volatile uint16_t *) 0xF0116)
+
+#define SCR00 (*(volatile uint16_t *) 0xF0118)
+
+#define SCR01 (*(volatile uint16_t *) 0xF011A)
+
+#define SCR02 (*(volatile uint16_t *) 0xF011C)
+
+#define SCR03 (*(volatile uint16_t *) 0xF011E)
+
+#define SS0L (*(volatile uint8_t *) 0xF0122)
+#define SS0L_bit (*(volatile __BITS8 *) 0xF0122)
+
+#define SPS0 (*(volatile uint16_t *) 0xF0126)
+
+#define SO0 (*(volatile uint16_t *) 0xF0128)
+
+#define SOE0L (*(volatile uint8_t *) 0xF012A)
+#define SOE0L_bit (*(volatile __BITS8 *) 0xF012A)
+
+#define SOL0 (*(volatile uint16_t *) 0xF0134)
+
+#define SSR11 (*(volatile uint16_t *) 0xF0142)
+
+#define SIR11 (*(volatile uint16_t *) 0xF014A)
+
+#define SMR11 (*(volatile uint16_t *) 0xF0152)
+
+#define SCR11 (*(volatile uint16_t *) 0xF015A)
+
+#define SS1L (*(volatile uint8_t *) 0xF0162)
+#define SS1L_bit (*(volatile __BITS8 *) 0xF0162)
+
+#define SPS1 (*(volatile uint16_t *) 0xF0166)
+
+#define SO1 (*(volatile uint16_t *) 0xF0168)
+
+#define SOE1L (*(volatile uint8_t *) 0xF016A)
+#define SOE1L_bit (*(volatile __BITS8 *) 0xF016A)
+
+#define TRJCR0 (*(volatile uint8_t * ) 0xF0240)
+
+#define TRJIOC0 (*(volatile uint8_t *) 0xF0241)
+#define TRJIOC0_bit (*(volatile __BITS8 *) 0xF0241)
+
+#define TRJMR0 (*(volatile uint8_t *) 0xF0242)
+#define TRJMR0_bit (*(volatile __BITS8 *) 0xF0242)
+
+#define TRJ0 (*(volatile uint16_t *) 0xF0500)
+
+
+#define P0 (*(volatile uint8_t *) 0xFFF00)
+#define P0_bit (*(volatile __BITS8 *) 0xFFF00)
+
+#define P1 (*(volatile uint8_t *) 0xFFF01)
+#define P1_bit (*(volatile __BITS8 *) 0xFFF01)
+
+#define P2 (*(volatile uint8_t *) 0xFFF02)
+#define P2_bit (*(volatile __BITS8 *) 0xFFF02)
+
+#define P3 (*(volatile uint8_t *) 0xFFF03)
+#define P3_bit (*(volatile __BITS8 *) 0xFFF03)
+
+#define P5 (*(volatile uint8_t *) 0xFFF05)
+#define P5_bit (*(volatile __BITS8 *) 0xFFF05)
+
+#define P6 (*(volatile uint8_t *) 0xFFF06)
+#define P6_bit (*(volatile __BITS8 *) 0xFFF06)
+
+#define P7 (*(volatile uint8_t *) 0xFFF07)
+#define P7_bit (*(volatile __BITS8 *) 0xFFF07)
+
+#define P12 (*(volatile uint8_t *) 0xFFF0C)
+#define P12_bit (*(volatile __BITS8 *) 0xFFF0C)
+
+#define P13 (*(volatile uint8_t *) 0xFFF0D)
+#define P13_bit (*(volatile __BITS8 *) 0xFFF0D)
+
+#define P14 (*(volatile uint8_t *) 0xFFF0E)
+#define P14_bit (*(volatile __BITS8 *) 0xFFF0E)
+
+#define SDR00 (*(volatile uint16_t *) 0xFFF10)
+
+#define SDR01 (*(volatile uint16_t *) 0xFFF12)
+
+#define ADCRH (*(volatile uint8_t *) 0xFFF1F)
+
+#define PM0 (*(volatile uint8_t *) 0xFFF20)
+#define PM0_bit (*(volatile __BITS8 *) 0xFFF20)
+
+#define PM1 (*(volatile uint8_t *) 0xFFF21)
+#define PM1_bit (*(volatile __BITS8 *) 0xFFF21)
+
+#define PM2 (*(volatile uint8_t *) 0xFFF22)
+#define PM2_bit (*(volatile __BITS8 *) 0xFFF22)
+
+#define PM3 (*(volatile uint8_t *) 0xFFF23)
+#define PM3_bit (*(volatile __BITS8 *) 0xFFF23)
+
+#define PM5 (*(volatile uint8_t *) 0xFFF25)
+#define PM5_bit (*(volatile __BITS8 *) 0xFFF25)
+
+#define PM6 (*(volatile uint8_t *) 0xFFF26)
+#define PM6_bit (*(volatile __BITS8 *) 0xFFF26)
+
+#define PM7 (*(volatile uint8_t *) 0xFFF27)
+#define PM7_bit (*(volatile __BITS8 *) 0xFFF27)
+
+#define PM12 (*(volatile uint8_t *) 0xFFF2C)
+#define PM12_bit (*(volatile __BITS8 *) 0xFFF2C)
+
+#define PM14 (*(volatile uint8_t *) 0xFFF2E)
+#define PM14_bit (*(volatile __BITS8 *) 0xFFF2E)
+
+#define ADM0 (*(volatile uint8_t *) 0xFFF30)
+#define ADM0_bit (*(volatile __BITS8 *) 0xFFF30)
+
+#define ADS (*(volatile uint8_t *) 0xFFF31)
+#define ADS_bit (*(volatile __BITS8 *) 0xFFF31)
+
+#define ADM1 (*(volatile uint8_t *) 0xFFF32)
+#define ADM1_bit (*(volatile __BITS8 *) 0xFFF32)
+
+#define KRM (*(volatile uint8_t *) 0xFFF37)
+#define KRM_bit (*(volatile __BITS8 *) 0xFFF37)
+
+#define EGP1 (*(volatile uint8_t *) 0xFFF3A)
+#define EGP1_bit (*(volatile __BITS8 *) 0xFFF3A)
+
+#define EGN1 (*(volatile uint8_t *) 0xFFF3B)
+#define EGN1_bit (*(volatile __BITS8 *) 0xFFF3B)
+
+#define SDR02 (*(volatile uint16_t *) 0xFFF44)
+
+#define SDR03 (*(volatile uint16_t *) 0xFFF46)
+
+#define SDR11 (*(volatile uint16_t *) 0xFFF4A)
+
+#define ITMC (*(volatile uint16_t *) 0xFFF90)
+
+#define CMC (*(volatile uint8_t *) 0xFFFA0)
+
+#define CSC (*(volatile uint8_t *) 0xFFFA1)
+#define CSC_bit (*(volatile __BITS8 *) 0xFFFA1)
+
+#define CKC (*(volatile uint8_t *) 0xFFFA4)
+#define CKC_bit (*(volatile __BITS8 *) 0xFFFA4)
+
+#define IF2L (*(volatile uint8_t *) 0xFFFD0)
+#define IF2L_bit (*(volatile __BITS8 *) 0xFFFD0)
+
+#define MK2L (*(volatile uint8_t *) 0xFFFD4)
+#define MK2L_bit (*(volatile __BITS8 *) 0xFFFD4)
+
+#define IF0H (*(volatile uint8_t *) 0xFFFE1)
+#define IF0H_bit (*(volatile __BITS8 *) 0xFFFE1)
+
+#define IF1L (*(volatile uint8_t *) 0xFFFE2)
+#define IF1L_bit (*(volatile __BITS8 *) 0xFFFE2)
+
+#define IF1H (*(volatile uint8_t *) 0xFFFE3)
+#define IF1H_bit (*(volatile __BITS8 *) 0xFFFE3)
+
+#define MK0H (*(volatile uint8_t *) 0xFFFE5)
+#define MK0H_bit (*(volatile __BITS8 *) 0xFFFE5)
+
+#define MK1L (*(volatile uint8_t *) 0xFFFE6)
+#define MK1L_bit (*(volatile __BITS8 *) 0xFFFE6)
+
+#define MK1H (*(volatile uint8_t *) 0xFFFE7)
+#define MK1H_bit (*(volatile __BITS8 *) 0xFFFE7)
--- /dev/null
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KLAVIRKO_GUI_H
+#define KLAVIRKO_GUI_H
+
+#include <stdint.h>
+#include "iodefine.h"
+// #include "iodefine_ext.h"
+
+#define LOWTEXT __attribute__ ((section (".lowtext")))
+#define LOWTEXT_INT __attribute__ ((interrupt)) LOWTEXT
+
+/* * * IO, SFR * * */
+
+//some names taken from schematic
+
+//POWER CONTROLL
+
+//DCDC_ENABLE_UC
+#define DCDC P0_bit.no0
+#define DCDC__PM PM0_bit.no0
+#define DCDC__POM POM0_bit.no0
+#define DCDC__PMC PMC0_bit.no0
+
+//UART
+
+//WIFI_RXD
+#define CTRL_TX P0_bit.no2
+#define CTRL_TX__PM PM0_bit.no2
+#define CTRL_TX__POM POM0_bit.no2
+#define CTRL_TX__PMC PMC0_bit.no2
+#define CTRL_TX__PU PU0_bit.no2
+
+#define CTRL_TX__SMR SMR02
+#define CTRL_TX__SCR SCR02
+#define CTRL_TX__SDR SDR02
+#define CTRL_TX__SSR SSR02
+#define CTRL_TX__SOE SOE0L_bit.no2
+#define CTRL_TX__SS SS0L_bit.no2
+#define CTRL_TX__IF IF1L_bit.no0
+#define CTRL_TX__MK MK1L_bit.no0
+
+//WIFI_TXD
+#define CTRL_RX P0_bit.no3
+#define CTRL_RX__PM PM0_bit.no3
+#define CTRL_RX__POM POM0_bit.no3
+#define CTRL_RX__PIM PIM0_bit.no3
+#define CTRL_RX__PMC PMC0_bit.no3
+#define CTRL_RX__PU PU0_bit.no3
+
+#define CTRL_RX__SMR SMR03
+#define CTRL_RX__SCR SCR03
+#define CTRL_RX__SDR SDR03
+#define CTRL_RX__SSR SSR03
+#define CTRL_RX__SIR SIR03
+#define CTRL_RX__SS SS0L_bit.no3
+#define CTRL_RX__IF IF1L_bit.no1
+#define CTRL_RX__MK MK1L_bit.no1
+#define CTRL_RX__MKE MK1L_bit.no2
+
+//UI_TXD
+#define AIX_TX P5_bit.no1
+#define AIX_TX__PM PM5_bit.no1
+#define AIX_TX__POM POM5_bit.no1
+#define AIX_TX__PU PU5_bit.no1
+
+#define AIX_TX__SMR SMR00
+#define AIX_TX__SCR SCR00
+#define AIX_TX__SDR SDR00
+#define AIX_TX__SSR SSR00
+#define AIX_TX__SOE SOE0L_bit.no0
+#define AIX_TX__SS SS0L_bit.no0
+#define AIX_TX__IF IF0H_bit.no5
+#define AIX_TX__MK MK0H_bit.no5
+
+//UI_RXD
+#define AIX_RX P5_bit.no0
+#define AIX_RX__PM PM5_bit.no0
+#define AIX_RX__POM POM5_bit.no0
+#define AIX_RX__PIM POM5_bit.no0
+#define AIX_RX__PU PU5_bit.no0
+
+#define AIX_RX__SMR SMR01
+#define AIX_RX__SCR SCR01
+#define AIX_RX__SDR SDR01
+#define AIX_RX__SSR SSR01
+#define AIX_RX__SIR SIR01
+#define AIX_RX__SS SS0L_bit.no1
+#define AIX_RX__IF IF0H_bit.no6
+#define AIX_RX__MK MK0H_bit.no6
+#define AIX_RX__MKE MK0H_bit.no7
+
+//SPI
+
+//FLASH_RESET
+#define FS_HOLD P6_bit.no3
+#define FS_HOLD__PM PM6_bit.no3
+
+//FLASH_WP
+#define FS_WP P6_bit.no2
+#define FS_WP__PM PM6_bit.no2
+
+//FLASH_CS
+#define FS_CS P7_bit.no3
+#define FS_CS__PM PM7_bit.no3
+#define FS_CS__PU PU7_bit.no3
+
+//FLASH_SCK
+#define FS_SCK P7_bit.no0
+#define FS_SCK__PM PM7_bit.no0
+#define FS_SCK__PU PU7_bit.no0
+
+//FLASH_MOSI
+#define FS_MOSI P7_bit.no2
+#define FS_MOSI__PM PM7_bit.no2
+#define FS_MOSI__PU PU7_bit.no2
+
+//FLASH_MISO
+#define FS_MISO P7_bit.no1
+#define FS_MISO__PM PM7_bit.no1
+#define FS_MISO__POM POM7_bit.no1
+#define FS_MISO__PU PU7_bit.no1
+
+#define FS__SMR SMR11
+#define FS__SCR SCR11
+#define FS__SDR SDR11
+#define FS__SSR SSR11
+#define FS__SIR SIR11
+#define FS__SOE SOE1L_bit.no1
+#define FS__SS SS1L_bit.no1
+
+//LCD
+
+//LCD_BACKLIGHT
+#define LCD_LIGHT P3_bit.no0
+#define LCD_LIGHT__PM PM3_bit.no0
+#define LCD_LIGHT__POM POM3_bit.no0
+#define LCD_LIGHT__PIM PIM3_bit.no0
+#define LCD_LIGHT__PU PU3_bit.no0
+#define LCD_LIGHT__IF IF1H_bit.no6
+#define LCD_LIGHT__MK MK1H_bit.no6
+
+//CONTRAST_READ
+#define LCD_CONTRAST__P P2_bit.no1
+#define LCD_CONTRAST__PM PM2_bit.no1
+
+//LCD_RSTB
+#define LCD_RSTB P3_bit.no1
+#define LCD_RSTB__PM PM3_bit.no1
+#define LCD_RSTB__PU PU3_bit.no1
+
+//LCD_CSB_MASTER
+#define LCD_CSB_MASTER P12_bit.no0
+#define LCD_CSB_MASTER__PM PM12_bit.no0
+#define LCD_CSB_MASTER__PMC PMC12_bit.no0
+
+//LCD_CSB_SLAVE
+#define LCD_CSB_SLAVE P13_bit.no0
+
+//LCD_WR
+#define LCD_WR P14_bit.no0
+#define LCD_WR__PM PM14_bit.no0
+#define LCD_WR__PU PU14_bit.no0
+
+//LCD_RD
+#define LCD_RD P14_bit.no6
+#define LCD_RD__PM PM14_bit.no6
+#define LCD_RD__PU PU14_bit.no6
+
+//LCD_AO
+#define LCD_A0 P14_bit.no7
+#define LCD_A0__PM PM14_bit.no7
+#define LCD_A0__PMC PMC14_bit.no7
+#define LCD_A0__PU PU14_bit.no7
+
+//LCD_D0 - LCD_D7
+#define LCD_D P1
+#define LCD_D__PM PM1
+#define LCD_D__PU PU1
+#define LCD_D__PIM PIM1
+#define LCD_D__POM POM1
+#define LCD_D__PMC PMC1
+
+//BUTTON
+
+//BUTTON_GROUP_0
+#define BUTTON_ABC__P P2_bit.no0
+#define BUTTON_ABC__PM PM2_bit.no0
+#define BUTTON_ABC__ADS 0x00
+
+//BUTTON_GROUP_2
+#define BUTTON_DEF__P P2_bit.no2
+#define BUTTON_DEF__PM PM2_bit.no2
+#define BUTTON_DEF__ADS 0x02
+
+//BUTTON_ON_OFF_UC
+#define BUTTON_X__P P13_bit.no7
+
+//BUTTON_RESUME_UC
+#define BUTTON_Y__P P7_bit.no7
+#define BUTTON_Y__PM PM7_bit.no7
+#define BUTTON_Y__PU PU7_bit.no7
+#define BUTTON_Y__KRM KRM_bit.no7
+#define BUTTON_Y__IF IF1H_bit.no3
+#define BUTTON_Y__MK MK1H_bit.no3
+
+//JOG_A
+#define JOG_A P7_bit.no4
+#define JOG_A__PM PM7_bit.no4
+#define JOG_A__POM POM7_bit.no4
+#define JOG_A__PU PU7_bit.no4
+#define JOG_A__EGP EGP1_bit.no0
+#define JOG_A__EGN EGN1_bit.no0
+#define JOG_A__MK MK2L_bit.no5
+#define JOG_A__IF IF2L_bit.no5
+
+//JOG_B
+#define JOG_B P7_bit.no5
+#define JOG_B__PM PM7_bit.no5
+#define JOG_B__PU PU7_bit.no5
+#define JOG_B__EGP EGP1_bit.no1
+#define JOG_B__EGN EGN1_bit.no1
+#define JOG_B__MK MK2L_bit.no6
+#define JOG_B__IF IF2L_bit.no6
+
+//LED
+
+//LED_0
+#define LED_U P2_bit.no5
+#define LED_U__PM PM2_bit.no5
+
+//LED_1
+#define LED_V P2_bit.no6
+#define LED_V__PM PM2_bit.no6
+
+//LED_2
+#define LED_W P2_bit.no7
+#define LED_W__PM PM2_bit.no7
+
+
+//at 32MHz
+#define NOP_1us() \
+{ \
+ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \
+ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \
+ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \
+ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \
+}
+
+//reset by executing from illegal memory access
+#define RESET_UI() \
+{ \
+ asm("br !!0xEF00;"); \
+}
+
+
+#endif
--- /dev/null
+/* LCD */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include "klavirko-ui.h"
+#include "lcd.h"
+#include "main.h"
+#include "debug.h"
+#include "font.h"
+
+volatile uint16_t lcdpwm_high;
+volatile uint16_t lcdpwm_low;
+volatile uint8_t lcdpwm_phase;
+
+ uint8_t lcd_mode[2] = {0xff, 0xff};
+ uint8_t lcd_x0[2] = {0xff, 0xff};
+ uint8_t lcd_x1[2] = {0x00, 0x00};
+ uint8_t lcd_y0[2] = {0xff, 0xff};
+ uint8_t lcd_y1[2] = {0x00, 0x00};
+
+const uint8_t wave_upper [12] = WAVE_UPPER;
+const uint8_t wave_middle[14] = WAVE_MIDDLE;
+const uint8_t wave_lower [12] = WAVE_LOWER;
+
+const uint8_t font8 [N_FONT8] = FONT8;
+const uint8_t font16[N_FONT16] = FONT16;
+
+const uint16_t button_pixels [N_BUTTONTYPES] = BUTTON_PIXELS;
+const uint16_t button_chars [N_BUTTONTYPES] = BUTTON_CHARS;
+const uint16_t button_lmargin[N_BUTTONTYPES] = BUTTON_LMARGIN;
+const uint16_t button_rmargin[N_BUTTONTYPES] = BUTTON_RMARGIN;
+
+
+inline void lcd_brightness (const uint16_t value)
+{
+ uint16_t x;
+
+ x = (((uint32_t)value)*((uint32_t)value))>>6;
+ lcdpwm_high = 64 + x;
+ lcdpwm_low = 16384 - x;
+}
+
+inline void lcd_contrast (const uint16_t value)
+{
+ uint32_t x;
+
+ x = value;
+ x *= LCD_Vop_SCALE;
+ x += LCD_Vop_OFFSET;
+ x>>= LCD_Vop_SHIFT;
+
+ if (x > LCD_Vop_MAX)
+ x = LCD_Vop_MAX;
+ else if (x < LCD_Vop_MIN)
+ x = LCD_Vop_MIN;
+
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_SetVop);
+ lcd_write(LCD_MASTER, LCD_DATA, x & LCD_Vop_LOWMASK);
+ lcd_write(LCD_MASTER, LCD_DATA, x >> LCD_Vop_HIGHSHIFT);
+}
+
+
+
+inline void setup_lcd (void)
+{
+ PER1 |= 0b00000001; //enable timer RJ
+
+ LCD_LIGHT__POM = 0;
+ LCD_LIGHT__PIM = 0;
+ LCD_LIGHT__PU = 0;
+ LCD_LIGHT__PM = 0;
+ LCD_LIGHT = 0;
+
+ LCD_RSTB__PM = 0;
+ LCD_RSTB = 0;
+
+ LCD_CSB_MASTER__PMC = 0;
+ LCD_CSB_MASTER__PM = 0;
+ LCD_CSB_MASTER = 1;
+
+ LCD_CSB_SLAVE = 1;
+
+ LCD_WR__PM = 0;
+ LCD_WR__PU = 0;
+ LCD_WR = 1;
+
+ LCD_RD__PM = 0;
+ LCD_RD__PU = 0;
+ LCD_RD = 1;
+
+ LCD_A0__PMC = 0;
+ LCD_A0__PM = 0;
+ LCD_A0__PU = 0;
+ LCD_A0 = 1;
+
+ LCD_D__PMC = 0x00;
+ LCD_D__POM = 0x00;
+ LCD_D__PIM = 0x00;
+ LCD_D__PU = 0x00;
+ LCD_D__PM = 0x00;
+ LCD_D = 0x00;
+
+ // lcd_brightness(0);
+ lcdpwm_high = 64;
+ lcdpwm_low = 16384;
+ lcdpwm_phase = 0;
+
+ TRJ0 = lcdpwm_high;
+ TRJIOC0 = 0b00000101; //enable output, start high
+ // TRJIOC0 = 0b00000001; //disable output
+ TRJMR0 = 0b00010001; //pulse mode, fclk/8 = 4MHz
+ // TRJMR0 = 0b00010000; //timer mode, fclk/8 = 4MHz
+ // LCD_LIGHT__MK = 0; //enable int. NOT NOW
+ // TRJCR0 = 0b00000001; //start timer NOT NOW!
+}
+
+inline void init_lcd (void)
+{
+ // most of this comes from datasheet, with some adjustment.
+ // uint16_t i,j;
+
+ //start LCD PWM timer and enable its interrupt
+ LCD_LIGHT__MK = 0;
+ TRJCR0 = 0b00000001;
+
+ //reset LCD
+ LCD_RSTB=0;
+ wait_ms(1 +1);
+ LCD_RSTB=1;
+ wait_ms(1 +1);
+
+ // Slave chip
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_EnableSlave);
+
+ // Disable auto read
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_ExtCommand2);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_AutoReadControl);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x9F);
+
+ // // Enable OTP Read
+ // lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_OtpWrRdControl);
+ // lcd_write(LCD_SLAVE, LCD_DATA, 0x00);
+
+ // wait_ms(10 +1);
+
+ // // OTP Up-Load
+ // lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_OtpRead);
+
+ // wait_ms(20 +1);
+
+ // // OTP Control Out
+ // lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_OtpControlWrite);
+
+ // Sleep out
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_PowerSaveSleepOut);
+
+ wait_ms(50 +1);
+
+ // Power control
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_PowerControl);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x01); // VB OFF; VR ON, VF OFF
+
+ // Display Mode
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_DisplayMode);
+ lcd_write(LCD_SLAVE, LCD_DATA, LCD_MONO); // Monochrome Mode
+
+ // Display Format
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_DataFormatLsbTop);
+
+ // Display Control
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_DisplayControl);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x00); // CL Dividing Ratio -> Not Divide
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x25); // Duty = 38
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x00); // CL Dividing Ratio -> Not Divide
+
+ // Data Scan Direction
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_DataScanDirection);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x06);
+
+ // Analog Circuit Set
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_ExtCommand2);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_AnalogCircuitSet);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x00);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x01); // Booster Efficiency = Level 1
+ lcd_write(LCD_SLAVE, LCD_DATA, LCD_BIAS); // Bias
+
+ // Page Address Setting
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_SetPageAddress);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0);
+ lcd_write(LCD_SLAVE, LCD_DATA, 4);
+
+ // Column Address Setting
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_SetColumnAddress);
+ lcd_write(LCD_SLAVE, LCD_DATA, 0);
+ lcd_write(LCD_SLAVE, LCD_DATA, 255);
+
+ // Display On
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_DisplayOn);
+
+ // Master chip
+
+ // Enable Master
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_EnableMaster);
+
+ // Disable auto read
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand2);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_AutoReadControl);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x9F);
+
+ // // Enable OTP Read
+ // lcd_write(LCD_MASTER, LCD_COMMAND, LCD_OtpWrRdControl);
+ // lcd_write(LCD_MASTER, LCD_DATA, 0x00);
+
+ // wait_ms(10 +1);
+
+ // // OTP Up-Load
+ // lcd_write(LCD_MASTER, LCD_COMMAND, LCD_OtpRead);
+
+ // wait_ms(20 +1);
+
+ // // OTP Control Out
+ // lcd_write(LCD_MASTER, LCD_COMMAND, LCD_OtpControlWrite);
+
+ // Sleep out
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_PowerSaveSleepOut);
+
+ wait_ms(50 +1);
+
+ // Power control
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_PowerControl);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x0B); // VB ON; VR, VF ON
+
+ // Set Vop
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_SetVop);
+ lcd_write(LCD_MASTER, LCD_DATA, LCD_DEFAULT_Vop );//!
+ lcd_write(LCD_MASTER, LCD_DATA, LCD_DEFAULT_Vop_HIGH );//!
+
+ // Display Mode
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DisplayMode);
+ lcd_write(LCD_MASTER, LCD_DATA, LCD_MONO); // Monochrome Mode
+
+ // Display Format
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DataFormatLsbTop);
+
+ // Display Control
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DisplayControl);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x00); // CL Dividing Ratio -> Not Divide
+ lcd_write(LCD_MASTER, LCD_DATA, 0x25); // Duty = 38
+ lcd_write(LCD_MASTER, LCD_DATA, 0x00); // CL Dividing Ratio -> Not Divide
+
+ // Data Scan Direction
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DataScanDirection);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x06);
+
+ // Analog Circuit Set
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand2);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_AnalogCircuitSet);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x00);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x01); // Booster Efficiency = Level
+ lcd_write(LCD_MASTER, LCD_DATA, LCD_BIAS); // Bias
+
+ // Page Address Setting
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_SetPageAddress);
+ lcd_write(LCD_MASTER, LCD_DATA, 0);
+ lcd_write(LCD_MASTER, LCD_DATA, 4);
+
+ // Column Address Setting
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_SetColumnAddress);
+ lcd_write(LCD_MASTER, LCD_DATA, 0);
+ lcd_write(LCD_MASTER, LCD_DATA, 255);
+
+ // Internal Power Supply
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand2);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DrivingSelectInt);
+
+ // Display On
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_ExtCommand1);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_DisplayOn);
+}
+
+
+
+// interrupt to generate brightness PWM.
+// FOR SOME REASON IT IS ON A PIN WITH TIMER OUTPUT BUT WITHOUT PWM :<
+inline void int_lcd_pwm (void)
+{
+ if(lcdpwm_phase)
+ {
+ // LCD_LIGHT = 1;
+ TRJ0 = lcdpwm_high;
+ lcdpwm_phase = 0;
+ }
+ else
+ {
+ // LCD_LIGHT = 0;
+ TRJ0 = lcdpwm_low;
+ lcdpwm_phase = 1;
+ }
+}
+
+void lcd_write ( // write single byte to LCD
+ const uint8_t chip,
+ const uint8_t cmd,
+ const uint8_t data
+)
+{
+ uint8_t d;
+
+ LCD_D__PM = 0x00; //data output
+
+ if (chip == LCD_SLAVE) //reverse bits for slave chip
+ d = reverse_bits(data);
+ else
+ d = data;
+
+ LCD_A0 = (cmd == LCD_DATA)?1:0; //set command/data
+
+ LCD_D = d; //set data
+
+ if(chip == LCD_MASTER) //set chipselect
+ LCD_CSB_MASTER=0;
+ else
+ LCD_CSB_SLAVE=0;
+
+ LCD_WR = 0; //set writeenable;
+ LCD_WR = 0;
+ // LCD_D = d; //set data
+
+ LCD_WR = 1; //unset writeenable;
+
+ if(chip == LCD_MASTER) //unset chipselect
+ LCD_CSB_MASTER=1;
+ else
+ LCD_CSB_SLAVE=1;
+
+ // LCD_D__PM = 0xff; //data back to input
+}
+
+inline void lcd_set_mode ( // setup drawing area and color depth for single chip
+ const uint8_t chip,
+ const uint8_t mode,
+ const uint8_t x0,
+ const uint8_t x1,
+ const uint8_t y0,
+ const uint8_t y1
+)
+{
+ if (lcd_mode[chip] != mode)
+ {
+ lcd_mode[chip] = mode;
+ lcd_write(chip, LCD_COMMAND, LCD_DisplayMode);
+ lcd_write(chip, LCD_DATA, mode);
+ }
+ if ((lcd_x0[chip] != x0)||(lcd_x1[chip] != x1))
+ {
+ lcd_x0[chip] = x0;
+ lcd_x1[chip] = x1;
+ lcd_write(chip, LCD_COMMAND, LCD_SetColumnAddress);
+ lcd_write(chip, LCD_DATA, x0);
+ lcd_write(chip, LCD_DATA, x1);
+ }
+ if ((lcd_y0[chip] != y0)||(lcd_y1[chip] != y1))
+ {
+ lcd_y0[chip] = y0;
+ lcd_y1[chip] = y1;
+ lcd_write(chip, LCD_COMMAND, LCD_SetPageAddress);
+ lcd_write(chip, LCD_DATA, y0);
+ lcd_write(chip, LCD_DATA, y1);
+ }
+}
+
+void lcd_setup_drawing ( // setup drawing area and color depth
+ const uint8_t mode,
+ const uint16_t x0,
+ const uint16_t x1,
+ const uint8_t y0,
+ const uint8_t y1
+)
+{
+ uint16_t x;
+ if(x0 < 256)
+ {
+ x = (x1>255) ? 255 : x1;
+ lcd_set_mode(LCD_SLAVE, mode, x0, x, y0, y1);
+ lcd_write(LCD_SLAVE, LCD_COMMAND, LCD_WriteDataToDDRAM);
+ }
+ if(x1 >= 256)
+ {
+ x = (x0<256) ? 0 : (x0-256);
+ lcd_set_mode(LCD_MASTER, mode, x, x1-256, y0, y1);
+ lcd_write(LCD_MASTER, LCD_COMMAND, LCD_WriteDataToDDRAM);
+ }
+}
+
+
+
+void lcd_clear_screen (const uint8_t mode)
+{
+ uint8_t y;
+ uint16_t i, j;
+
+ y = (mode == LCD_GRAY) ? 9 : 4;
+
+ lcd_setup_drawing(mode, 0, 511, 0, y);
+ for(i=0; i<=255; ++i)
+ {
+ for(j=0; j<=y; ++j)
+ {
+ lcd_write(LCD_SLAVE, LCD_DATA, 0x00);
+ lcd_write(LCD_MASTER, LCD_DATA, 0x00);
+ }
+ }
+}
+
+void lcd_draw_wave (const uint8_t * const data)
+{
+ uint16_t i;
+ uint8_t col[10];
+ uint8_t x;
+
+ lcd_setup_drawing(LCD_GRAY, 0, 255, 0, 9);
+
+ // convert shape to bit patterns & then draw
+ for (i=0; i<256; ++i)
+ {
+ memset(col, 0, 10);
+ x = data[i];
+
+ if (x < WAVE_LOWER_0)
+ {
+ col[4] = WAVE_LOWER_START;
+ if (x < WAVE_LOWER_1)
+ {
+ col[5] = 0xff;
+ if (x < WAVE_LOWER_2)
+ {
+ col[6] = 0xff;
+ if (x < WAVE_LOWER_3)
+ {
+ col[7] = 0xff;
+ if (x < WAVE_LOWER_4)
+ {
+ col[8] = 0xff;
+ col[9] = wave_lower[x-WAVE_LOWER_5];
+ }
+ else
+ col[8] = wave_lower[x-WAVE_LOWER_4];
+ }
+ else
+ col[7] = wave_lower[x-WAVE_LOWER_3];
+ }
+ else
+ col[6] = wave_lower[x-WAVE_LOWER_2];
+ }
+ else
+ col[5] = wave_lower[x-WAVE_LOWER_1];
+ }
+ else if (x >= WAVE_UPPER_0)
+ {
+ col[4] = WAVE_UPPER_START;
+ if (x >= WAVE_UPPER_1)
+ {
+ col[3] = 0xff;
+ if (x >= WAVE_UPPER_2)
+ {
+ col[2] = 0xff;
+ if (x >= WAVE_UPPER_3)
+ {
+ col[1] = 0xff;
+ col[0] = wave_upper[x-WAVE_UPPER_3];
+ }
+ else
+ col[1] = wave_upper[x-WAVE_UPPER_2];
+ }
+ else
+ col[2] = wave_upper[x-WAVE_UPPER_1];
+ }
+ else
+ col[3] = wave_upper[x-WAVE_UPPER_0];
+ }
+ else
+ {
+ col[4] = wave_middle[x-WAVE_LOWER_0];
+ }
+
+ lcd_write(LCD_SLAVE, LCD_DATA, col[0]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[1]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[2]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[3]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[4]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[5]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[6]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[7]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[8]);
+ lcd_write(LCD_SLAVE, LCD_DATA, col[9]);
+ }
+}
+
+void lcd_draw_adsr (const uint8_t * const data)
+{
+ uint16_t i;
+ uint8_t col[10];
+ uint8_t x;
+
+ lcd_setup_drawing(LCD_GRAY, 256, 511, 0, 9);
+
+ // convert shape to bit patterns & then draw
+ for (i=0; i<256; ++i)
+ {
+ memset(col, 0, 10);
+ x = data[i];
+
+ if (x >= ADSR_UPPER_1)
+ {
+ col[9] = 0xff;
+ if (x >= ADSR_UPPER_2)
+ {
+ col[8] = 0xff;
+ if (x >= ADSR_UPPER_3)
+ {
+ col[7] = 0xff;
+ if (x >= ADSR_UPPER_4)
+ {
+ col[6] = 0xff;
+ if (x >= ADSR_UPPER_5)
+ {
+ col[5] = 0xff;
+ if (x >= ADSR_UPPER_6)
+ {
+ col[4] = 0xff;
+ if (x >= ADSR_UPPER_7)
+ {
+ col[3] = 0xff;
+ if (x >= ADSR_UPPER_8)
+ {
+ col[2] = 0xff;
+ if (x >= ADSR_UPPER_9)
+ {
+ col[1] = 0xff;
+ col[0] = wave_upper[x-ADSR_UPPER_9];
+ }
+ else
+ col[1] = wave_upper[x-ADSR_UPPER_8];
+ }
+ else
+ col[2] = wave_upper[x-ADSR_UPPER_7];
+ }
+ else
+ col[3] = wave_upper[x-ADSR_UPPER_6];
+ }
+ else
+ col[4] = wave_upper[x-ADSR_UPPER_5];
+ }
+ else
+ col[5] = wave_upper[x-ADSR_UPPER_4];
+ }
+ else
+ col[6] = wave_upper[x-ADSR_UPPER_3];
+ }
+ else
+ col[7] = wave_upper[x-ADSR_UPPER_2];
+ }
+ else
+ col[8] = wave_upper[x-ADSR_UPPER_1];
+ }
+ else
+ col[9] = wave_upper[x-ADSR_UPPER_0];
+
+ lcd_write(LCD_MASTER, LCD_DATA, col[0]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[1]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[2]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[3]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[4]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[5]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[6]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[7]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[8]);
+ lcd_write(LCD_MASTER, LCD_DATA, col[9]);
+ }
+}
+
+void lcd_subdraw_button (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+)
+{
+ uint16_t line1, line2, line3, line4, margin_l, margin_r;
+ uint16_t len, N;
+ uint16_t i, i0, i1, i2, i3, j0, j1, j2, j3;
+ uint8_t chip = LCD_SLAVE;
+
+ line1 = button_chars[type];
+ margin_l = button_lmargin[type];
+ margin_r = button_rmargin[type];
+
+ line2 = line1 + line1;
+ line3 = line2 + line1;
+ line4 = line3 + line1;
+
+ N = line1 <<3;
+
+ len = (uint16_t) strlen(text);
+ if (len>line4)
+ len = line4;
+
+ for(i=0; i<margin_l; ++i) // left margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+
+ if (len <= line1) // single text line; 16px font
+ {
+ for (i=0, i0=-1; i<N; ++i)
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ if (i0 < len)
+ j0=text[i0]<<4;
+ else
+ j0 = 0;
+ }
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+ }
+ else if (len <= line2) // 2 text lines; 16px font
+ {
+ for (i=0, i0=-1, i1=line1-1; i<N; ++i)
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ ++i1;
+ j0=text[i0]<<4;
+ if (i1 < len)
+ j1=text[i1]<<4;
+ else
+ j1 = 0;
+ }
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font16[j1]);
+ ++j1;
+ lcd_write(chip, LCD_DATA, font16[j1]);
+ ++j1;
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+ }
+ else if (len <= line3) // 3 text lines; 8px font
+ {
+ for (i=0, i0=-1, i1=line1-1, i2=line2-1; i<N; ++i)
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ ++i1;
+ ++i2;
+ j0=text[i0]<<3;
+ j1=text[i1]<<3;
+ if (i2 < len)
+ j2=text[i2]<<3;
+ else
+ j2 = 0;
+ }
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, font8[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font8[j1]);
+ ++j1;
+ lcd_write(chip, LCD_DATA, font8[j2]);
+ ++j2;
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+ }
+ else // 4 text lines; 8px font
+ {
+ for (i=0, i0=-1, i1=line1-1, i2=line2-1, i3=line3-1; i<N; ++i)
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ ++i1;
+ ++i2;
+ ++i3;
+ j0=text[i0]<<3;
+ j1=text[i1]<<3;
+ j2=text[i2]<<3;
+ if (i3 < len)
+ j3=text[i3]<<3;
+ else
+ j3 = 0;
+ }
+ lcd_write(chip, LCD_DATA, font8[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font8[j1]);
+ ++j1;
+ lcd_write(chip, LCD_DATA, font8[j2]);
+ ++j2;
+ lcd_write(chip, LCD_DATA, font8[j3]);
+ ++j3;
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+ }
+ for(i=0; i<margin_r; ++i) // right margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+}
+
+void lcd_subdraw_lowbutton8 (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+)
+{
+ uint16_t line1, margin_l, margin_r;
+ uint16_t len, N;
+ uint16_t i, i0, j0, j3;
+ uint8_t chip = LCD_SLAVE;
+
+ line1 = button_chars[type];
+ margin_l = button_lmargin[type];
+ margin_r = button_rmargin[type];
+
+ N = line1 <<3;
+
+ len = (uint16_t) strlen(text);
+ if (len>line1)
+ len = line1;
+
+ for(i=0; i<margin_l; ++i) // left margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+
+ for (i=0, i0=-1; i<N; ++i) // single text line; 8 font
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ if (i0 < len)
+ j0=text[i0]<<3;
+ else
+ j0 = 0;
+ }
+ lcd_write(chip, LCD_DATA, font8[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+
+ for(i=0; i<margin_r; ++i) // right margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+}
+
+void lcd_subdraw_lowbutton16 (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+)
+{
+ uint16_t line1, margin_l, margin_r;
+ uint16_t len, N;
+ uint16_t i, i0, j0, j3;
+ uint8_t chip = LCD_SLAVE;
+
+ line1 = button_chars[type];
+ margin_l = button_lmargin[type];
+ margin_r = button_rmargin[type];
+
+ N = line1 <<3;
+
+ len = (uint16_t) strlen(text);
+ if (len>line1)
+ len = line1;
+
+ for(i=0; i<margin_l; ++i) // left margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+
+ for (i=0, i0=-1; i<N; ++i) // single text line; 16px font
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ if(!(i&0x7))
+ {
+ ++i0;
+ if (i0 < len)
+ j0=text[i0]<<4;
+ else
+ j0 = 0;
+ }
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ lcd_write(chip, LCD_DATA, font16[j0]);
+ ++j0;
+ ++(*x);
+ }
+
+ for(i=0; i<margin_r; ++i) // right margin
+ {
+ if (*x >= 256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ lcd_write(chip, LCD_DATA, 0x00);
+ ++(*x);
+ }
+}
+
+void lcd_subdraw_divider (uint16_t * const x)
+{
+ uint8_t chip = LCD_SLAVE;
+
+ if (*x >= 256)
+ chip = LCD_MASTER;
+
+ lcd_write(chip, LCD_DATA, 0x55);
+ lcd_write(chip, LCD_DATA, 0x55);
+ lcd_write(chip, LCD_DATA, 0x55);
+ lcd_write(chip, LCD_DATA, 0x55);
+ lcd_write(chip, LCD_DATA, 0x55);
+
+ ++(*x);
+}
+
+void lcd_subdraw_lowdivider (uint16_t * const x)
+{
+ uint8_t chip = LCD_SLAVE;
+
+ if (*x >= 256)
+ chip = LCD_MASTER;
+
+ lcd_write(chip, LCD_DATA, 0x55);
+ lcd_write(chip, LCD_DATA, 0x55);
+
+ ++(*x);
+}
+
+void lcd_draw_menu (
+ const uint8_t buttons,
+ const uint8_t * const title,
+ const uint8_t * const button_0,
+ const uint8_t * const button_A,
+ const uint8_t * const button_B,
+ const uint8_t * const button_C,
+ const uint8_t * const button_D,
+ const uint8_t * const button_E,
+ const uint8_t * const button_F
+){
+ uint16_t x=0;
+
+ lcd_setup_drawing(LCD_MONO, 0, 511, 0, 4);
+
+ lcd_subdraw_button (&x, FULLTEXT - buttons, title);
+ switch (buttons)
+ {
+ case 7:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_0);
+ case 6:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_A);
+ case 5:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_B);
+ case 4:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_C);
+ case 3:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_D);
+ case 2:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_E);
+ case 1:
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, button_F);
+ case 0:
+ default:
+ break;
+ }
+}
+
+void lcd_update_button (
+ const int8_t id,
+ const uint8_t * const text
+)
+{
+ uint16_t x;
+
+ x = TITLE_6B_PIXELS + 1 + id * (BUTTON_1X_PIXELS + 1);
+
+ lcd_setup_drawing(LCD_MONO, x, x+BUTTON_1X_PIXELS-1, 0, 4);
+
+ lcd_subdraw_button (&x, 0, text);
+}
+
+void lcd_draw_name_cursor (const uint8_t pos)
+{
+ uint16_t x, i, j;
+ uint8_t chip = LCD_SLAVE;
+
+ x = (pos<<3) + TITLE_6B_PIXELS + 1 +BUTTON_6X_LMARGIN;
+ lcd_setup_drawing(LCD_MONO, x, x+7, 2, 2);
+
+ for (i=x, j='^'<<3; i<x+8; ++i, j+=1)
+ {
+ if (i>=256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, font8[j]);
+ }
+}
+
+void lcd_erase_name_cursor (const uint8_t pos)
+{
+ uint16_t x, i;
+ uint8_t chip = LCD_SLAVE;
+
+ x = (pos<<3) + TITLE_6B_PIXELS + 1 +BUTTON_6X_LMARGIN;
+ lcd_setup_drawing(LCD_MONO, x, x+7, 2, 2);
+
+ for (i=x; i<x+8; ++i)
+ {
+ if (i>=256)
+ chip = LCD_MASTER;
+ lcd_write(chip, LCD_DATA, 0x00);
+ }
+}
+
+void lcd_draw_name_list (const uint8_t * const list)
+{
+ uint16_t x;
+
+ x = TITLE_6B_PIXELS + 1;
+ lcd_setup_drawing(LCD_MONO, x, 511, 0, 1);
+ lcd_subdraw_lowbutton16(&x, BUTTON_6X, list);
+}
+
+void lcd_draw_name_menu (
+ const uint8_t * const title,
+ const uint8_t * const list,
+ const uint8_t cursor,
+ const uint8_t * const name,
+ const uint8_t * const button_A,
+ const uint8_t * const button_B,
+ const uint8_t * const button_C,
+ const uint8_t * const button_D,
+ const uint8_t * const button_E,
+ const uint8_t * const button_F
+)
+{
+ uint16_t x = 0;
+ lcd_clear_screen(LCD_MONO);
+ lcd_setup_drawing(LCD_MONO, 0, TITLE_6B_PIXELS, 0, 4);
+
+ lcd_subdraw_button (&x, TITLE_7B, title);
+ lcd_subdraw_divider(&x);
+ lcd_subdraw_button (&x, BUTTON_1X, name);
+ lcd_subdraw_divider(&x);
+
+ lcd_setup_drawing(LCD_MONO, x, 511, 3, 4);
+
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_A);
+ lcd_subdraw_lowdivider(&x);
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_B);
+ lcd_subdraw_lowdivider(&x);
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_C);
+ lcd_subdraw_lowdivider(&x);
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_D);
+ lcd_subdraw_lowdivider(&x);
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_E);
+ lcd_subdraw_lowdivider(&x);
+ lcd_subdraw_lowbutton8(&x, BUTTON_1X, button_F);
+
+ lcd_draw_name_list(list);
+
+ lcd_draw_name_cursor(cursor);
+}
--- /dev/null
+/* LCD */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+// #include "font.h"
+
+/* screen layout
+
+| 256 | 256 |
++-------------+----+----+----+----+----+----+
+| | | | | | | |
++-------------+----+----+----+----+----+----+
+| 146 1 60 1 60 1 60 1 60 1 60 1 60 |
+
+|2| 7x8 |2|
++-+-------+-+
+| |acbdefg| |
++-+-------+-+
+| 60 |
+
+| 18x8 |2|
++------------------+-+
+|abcdefghijklmnopqr| |
++------------------+-|
+| 146 |
+
+*/
+
+#define N_FONT8 (256 * 1 * 8)
+#define N_FONT16 (256 * 2 * 8)
+
+#define BUTTON_1X_PIXELS 60
+#define BUTTON_2X_PIXELS 121
+#define BUTTON_3X_PIXELS 182
+#define BUTTON_4X_PIXELS 243
+#define BUTTON_5X_PIXELS 304
+#define BUTTON_6X_PIXELS 365
+#define BUTTON_7X_PIXELS 426
+#define BUTTON_8X_PIXELS 487
+#define TITLE_8B_PIXELS 24
+#define TITLE_7B_PIXELS 85
+#define TITLE_6B_PIXELS 146
+#define TITLE_5B_PIXELS 207
+#define TITLE_4B_PIXELS 268
+#define TITLE_3B_PIXELS 329
+#define TITLE_2B_PIXELS 390
+#define TITLE_1B_PIXELS 451
+#define FULLTEXT_PIXELS 512
+
+#define BUTTON_1X_CHARS 7
+#define BUTTON_2X_CHARS 14
+#define BUTTON_3X_CHARS 22
+#define BUTTON_4X_CHARS 29
+#define BUTTON_5X_CHARS 37
+#define BUTTON_6X_CHARS 45
+#define BUTTON_7X_CHARS 53
+#define BUTTON_8X_CHARS 60
+#define TITLE_8B_CHARS 3
+#define TITLE_7B_CHARS 10
+#define TITLE_6B_CHARS 18
+#define TITLE_5B_CHARS 25
+#define TITLE_4B_CHARS 33
+#define TITLE_3B_CHARS 41
+#define TITLE_2B_CHARS 48
+#define TITLE_1B_CHARS 56
+#define FULLTEXT_CHARS 64
+
+#define BUTTON_1X_LMARGIN 2
+#define BUTTON_2X_LMARGIN 4
+#define BUTTON_3X_LMARGIN 3
+#define BUTTON_4X_LMARGIN 5
+#define BUTTON_5X_LMARGIN 4
+#define BUTTON_6X_LMARGIN 2
+#define BUTTON_7X_LMARGIN 1
+#define BUTTON_8X_LMARGIN 3
+#define TITLE_8B_LMARGIN 0
+#define TITLE_7B_LMARGIN 0
+#define TITLE_6B_LMARGIN 0
+#define TITLE_5B_LMARGIN 0
+#define TITLE_4B_LMARGIN 0
+#define TITLE_3B_LMARGIN 0
+#define TITLE_2B_LMARGIN 0
+#define TITLE_1B_LMARGIN 0
+#define FULLTEXT_LMARGIN 0
+
+#define BUTTON_1X_RMARGIN 2
+#define BUTTON_2X_RMARGIN 5
+#define BUTTON_3X_RMARGIN 3
+#define BUTTON_4X_RMARGIN 6
+#define BUTTON_5X_RMARGIN 4
+#define BUTTON_6X_RMARGIN 3
+#define BUTTON_7X_RMARGIN 1
+#define BUTTON_8X_RMARGIN 4
+#define TITLE_8B_RMARGIN 0
+#define TITLE_7B_RMARGIN 5
+#define TITLE_6B_RMARGIN 2
+#define TITLE_5B_RMARGIN 7
+#define TITLE_4B_RMARGIN 4
+#define TITLE_3B_RMARGIN 1
+#define TITLE_2B_RMARGIN 6
+#define TITLE_1B_RMARGIN 3
+#define FULLTEXT_RMARGIN 0
+
+#define BUTTON_1X 0
+#define BUTTON_2X 1
+#define BUTTON_3X 2
+#define BUTTON_4X 3
+#define BUTTON_5X 4
+#define BUTTON_6X 5
+#define BUTTON_7X 6
+#define BUTTON_8X 7
+#define TITLE_8B 8
+#define TITLE_7B 9
+#define TITLE_6B 10
+#define TITLE_5B 11
+#define TITLE_4B 12
+#define TITLE_3B 13
+#define TITLE_2B 14
+#define TITLE_1B 15
+#define FULLTEXT 16
+#define N_BUTTONTYPES 17
+
+#define BUTTON_PIXELS { \
+ BUTTON_1X_PIXELS, \
+ BUTTON_2X_PIXELS, \
+ BUTTON_3X_PIXELS, \
+ BUTTON_4X_PIXELS, \
+ BUTTON_5X_PIXELS, \
+ BUTTON_6X_PIXELS, \
+ BUTTON_7X_PIXELS, \
+ BUTTON_8X_PIXELS, \
+ TITLE_8B_PIXELS, \
+ TITLE_7B_PIXELS, \
+ TITLE_6B_PIXELS, \
+ TITLE_5B_PIXELS, \
+ TITLE_4B_PIXELS, \
+ TITLE_3B_PIXELS, \
+ TITLE_2B_PIXELS, \
+ TITLE_1B_PIXELS, \
+ FULLTEXT_PIXELS, \
+}
+
+#define BUTTON_CHARS { \
+ BUTTON_1X_CHARS, \
+ BUTTON_2X_CHARS, \
+ BUTTON_3X_CHARS, \
+ BUTTON_4X_CHARS, \
+ BUTTON_5X_CHARS, \
+ BUTTON_6X_CHARS, \
+ BUTTON_7X_CHARS, \
+ BUTTON_8X_CHARS, \
+ TITLE_8B_CHARS, \
+ TITLE_7B_CHARS, \
+ TITLE_6B_CHARS, \
+ TITLE_5B_CHARS, \
+ TITLE_4B_CHARS, \
+ TITLE_3B_CHARS, \
+ TITLE_2B_CHARS, \
+ TITLE_1B_CHARS, \
+ FULLTEXT_CHARS, \
+}
+
+#define BUTTON_LMARGIN { \
+ BUTTON_1X_LMARGIN, \
+ BUTTON_2X_LMARGIN, \
+ BUTTON_3X_LMARGIN, \
+ BUTTON_4X_LMARGIN, \
+ BUTTON_5X_LMARGIN, \
+ BUTTON_6X_LMARGIN, \
+ BUTTON_7X_LMARGIN, \
+ BUTTON_8X_LMARGIN, \
+ TITLE_8B_LMARGIN, \
+ TITLE_7B_LMARGIN, \
+ TITLE_6B_LMARGIN, \
+ TITLE_5B_LMARGIN, \
+ TITLE_4B_LMARGIN, \
+ TITLE_3B_LMARGIN, \
+ TITLE_2B_LMARGIN, \
+ TITLE_1B_LMARGIN, \
+ FULLTEXT_LMARGIN, \
+}
+
+#define BUTTON_RMARGIN { \
+ BUTTON_1X_RMARGIN, \
+ BUTTON_2X_RMARGIN, \
+ BUTTON_3X_RMARGIN, \
+ BUTTON_4X_RMARGIN, \
+ BUTTON_5X_RMARGIN, \
+ BUTTON_6X_RMARGIN, \
+ BUTTON_7X_RMARGIN, \
+ BUTTON_8X_RMARGIN, \
+ TITLE_8B_RMARGIN, \
+ TITLE_7B_RMARGIN, \
+ TITLE_6B_RMARGIN, \
+ TITLE_5B_RMARGIN, \
+ TITLE_4B_RMARGIN, \
+ TITLE_3B_RMARGIN, \
+ TITLE_2B_RMARGIN, \
+ TITLE_1B_RMARGIN, \
+ FULLTEXT_RMARGIN, \
+}
+
+//The LCD driver is ST75256.
+
+/*
+voltage, contrast, bias, settings, limits...
+
+85 <= Vop <= 360
+V0 = 3.6 + Vop * 0.04
+VG = 2 * V0 / N
+N = [9, 10, 11, 12, 13, 14]
+VG >= 1.8
+V0 <=18
+
+therefore:
+
+ | V0/ | min | min | Vop |
+ N | /VG| V0 | Vop |range|
+---+-----+-----+-----+-----+
+ 9 | 4.5 | 8.1 | 113 | 247 | <-- our choice
+10 | 5.0 | 9.0 | 135 | 225 |
+11 | 5.5 | 9.9 | 158 | 202 |
+12 | 6.0 |10.8 | 180 | 180 |
+13 | 6.5 |11.7 | 203 | 157 |
+14 | 7.0 |12.6 | 225 | 135 |
+
+*/
+
+#define LCD_BIAS_14 0
+#define LCD_BIAS_13 1
+#define LCD_BIAS_12 2
+#define LCD_BIAS_11 3
+#define LCD_BIAS_10 4
+#define LCD_BIAS_9 5
+
+#define LCD_BIAS LCD_BIAS_9
+
+#define LCD_Vop_MIN_14 225
+#define LCD_Vop_MIN_13 203
+#define LCD_Vop_MIN_12 180
+#define LCD_Vop_MIN_11 158
+#define LCD_Vop_MIN_10 135
+#define LCD_Vop_MIN_9 113
+
+#define LCD_Vop_MAX 360
+
+
+#if LCD_BIAS == LCD_BIAS_14
+ #define LCD_Vop_MIN LCD_Vop_MIN_14
+#elif LCD_BIAS == LCD_BIAS_13
+ #define LCD_Vop_MIN LCD_Vop_MIN_13
+#elif LCD_BIAS == LCD_BIAS_12
+ #define LCD_Vop_MIN LCD_Vop_MIN_12
+#elif LCD_BIAS == LCD_BIAS_11
+ #define LCD_Vop_MIN LCD_Vop_MIN_11
+#elif LCD_BIAS == LCD_BIAS_10
+ #define LCD_Vop_MIN LCD_Vop_MIN_10
+#elif LCD_BIAS == LCD_BIAS_9
+ #define LCD_Vop_MIN LCD_Vop_MIN_9
+#endif
+
+#define LCD_Vop_SCALE (LCD_Vop_MAX - LCD_Vop_MIN)
+
+#define LCD_Vop_SHIFT 10
+
+#define LCD_Vop_OFFSET ((1 << (LCD_Vop_SHIFT-1)) + ((uint32_t)LCD_Vop_MIN << LCD_Vop_SHIFT))
+
+#define LCD_Vop_LOWMASK 0x3F
+#define LCD_Vop_HIGHSHIFT 6
+
+#define LCD_DEFAULT_Vop 180
+#define LCD_DEFAULT_Vop_LOW (LCD_DEFAULT_Vop & LCD_Vop_LOWMASK)
+#define LCD_DEFAULT_Vop_HIGH (LCD_DEFAULT_Vop >> LCD_Vop_HIGHSHIFT)
+
+#define LCD_MASTER 0
+#define LCD_SLAVE 1
+
+#define LCD_COMMAND 0
+#define LCD_DATA 1
+
+#define LCD_MONO 0x10
+#define LCD_GRAY 0x11
+
+//LCD commands
+
+//ext
+#define LCD_ExtCommand1 0x30
+#define LCD_ExtCommand2 0x31
+#define LCD_ExtCommand3 0x38
+#define LCD_ExtCommand4 0x39
+//ext1
+#define LCD_DisplayOn 0xAF
+#define LCD_DisplayOff 0xAE
+#define LCD_DisplayNormal 0xA6
+#define LCD_DisplayInverse 0xA7
+#define LCD_AllPixelOn 0x23
+#define LCD_AllPixelOff 0x22
+#define LCD_DisplayControl 0xCA
+#define LCD_PowerSaveSleepIn 0x95
+#define LCD_PowerSaveSleepOut 0x94
+#define LCD_SetPageAddress 0x75
+#define LCD_SetColumnAddress 0x15
+#define LCD_DataScanDirection 0xBC
+#define LCD_WriteDataToDDRAM 0x5C
+#define LCD_PartialIn 0xA8
+#define LCD_PartialOut 0xA9
+#define LCD_OscOn 0xD1
+#define LCD_OscOff 0xD2
+#define LCD_PowerControl 0x20
+#define LCD_SetVop 0x81
+#define LCD_VopIncrease 0xD6
+#define LCD_VopDecrease 0xD7
+#define LCD_ReadContrastLo 0x7C
+#define LCD_ReadContrastHi 0x7D
+#define LCD_Nop 0x25
+#define LCD_DataFormatLsbTop 0x0C
+#define LCD_DataFormatLsbBottom 0x08
+#define LCD_DisplayMode 0xF0
+#define LCD_EnableMaster 0x6E
+#define LCD_EnableSlave 0x6F
+#define LCD_ReadStatus 0x6F
+//ext2
+#define LCD_AnalogCircuitSet 0x32
+#define LCD_BoosterLevel 0x51
+#define LCD_DrivingSelectInt 0x40
+#define LCD_DrivingSelectExt 0x41
+#define LCD_AutoReadControl 0xD7
+#define LCD_OtpWrRdControl 0xE0
+#define LCD_OtpControlWrite 0xE1
+#define LCD_OtpWrite 0xE2
+#define LCD_OtpRead 0xE3
+#define LCD_OtpSelectionControl 0xE4
+
+
+// bit patterns to display the waveform
+#define WAVE_UPPER \
+{ \
+ 0x40, 0x80, 0xc0, \
+ 0xd0, 0xe0, 0xf0, \
+ 0xf4, 0xf8, 0xfc, \
+ 0xfd, 0xfe, 0xff \
+}
+#define WAVE_MIDDLE \
+{ \
+ 0xc0, 0x80, 0x40, \
+ 0x00, 0x10, 0x20, \
+ 0x30, 0x34, 0x38, \
+ 0x3c, 0x3d, 0x3e, \
+ 0x3f \
+}
+#define WAVE_LOWER \
+{ \
+ 0xff, 0xbf, 0x7f, \
+ 0x3f, 0x2f, 0x1f, \
+ 0x0f, 0x0b, 0x07, \
+ 0x03, 0x02, 0x01 \
+}
+#define WAVE_LOWER_START 0xc0
+#define WAVE_UPPER_START 0x3f
+
+#define WAVE_LOWER_0 54
+#define WAVE_LOWER_1 42
+#define WAVE_LOWER_2 30
+#define WAVE_LOWER_3 18
+#define WAVE_LOWER_4 6
+#define WAVE_LOWER_5 (-6)
+
+#define WAVE_UPPER_0 67
+#define WAVE_UPPER_1 79
+#define WAVE_UPPER_2 91
+#define WAVE_UPPER_3 103
+
+#define ADSR_UPPER_0 (-5)
+#define ADSR_UPPER_1 7
+#define ADSR_UPPER_2 19
+#define ADSR_UPPER_3 31
+#define ADSR_UPPER_4 43
+#define ADSR_UPPER_5 55
+#define ADSR_UPPER_6 67
+#define ADSR_UPPER_7 79
+#define ADSR_UPPER_8 91
+#define ADSR_UPPER_9 103
+
+
+inline void lcd_brightness (const uint16_t value);
+inline void lcd_contrast (const uint16_t value);
+
+inline void setup_lcd (void);
+inline void init_lcd (void);
+
+inline void int_lcd_pwm (void) LOWTEXT_INT;
+
+void lcd_write ( // write single byte to LCD
+ const uint8_t chip,
+ const uint8_t cmd,
+ const uint8_t data
+);
+inline void lcd_set_mode ( // setup drawing area and color depth for single chip
+ const uint8_t chip,
+ const uint8_t mode,
+ const uint8_t x0,
+ const uint8_t x1,
+ const uint8_t y0,
+ const uint8_t y1
+);
+void lcd_setup_drawing ( // setup drawing area and color depth
+ const uint8_t mode,
+ const uint16_t x0,
+ const uint16_t x1,
+ const uint8_t y0,
+ const uint8_t y1
+);
+
+void lcd_clear_screen (const uint8_t mode);
+void lcd_draw_wave (const uint8_t * const data);
+void lcd_draw_adsr (const uint8_t * const data);
+void lcd_subdraw_button (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+);
+void lcd_subdraw_lowbutton8 (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+);
+void lcd_subdraw_lowbutton16 (
+ uint16_t * const x,
+ const uint8_t type,
+ const uint8_t * const text
+);
+void lcd_subdraw_divider (uint16_t * const x);
+void lcd_draw_menu (
+ const uint8_t buttons,
+ const uint8_t * const title,
+ const uint8_t * const button_0,
+ const uint8_t * const button_A,
+ const uint8_t * const button_B,
+ const uint8_t * const button_C,
+ const uint8_t * const button_D,
+ const uint8_t * const button_E,
+ const uint8_t * const button_F
+);
+void lcd_update_button (
+ const int8_t id,
+ const uint8_t * const text
+);
+void lcd_draw_name_cursor(const uint8_t pos);
+void lcd_erase_name_cursor(const uint8_t pos);
+void lcd_draw_name_list (const uint8_t * const list);
+void lcd_draw_name_menu (
+ const uint8_t * const title,
+ const uint8_t * const list,
+ const uint8_t cursor,
+ const uint8_t * const name,
+ const uint8_t * const button_A,
+ const uint8_t * const button_B,
+ const uint8_t * const button_C,
+ const uint8_t * const button_D,
+ const uint8_t * const button_E,
+ const uint8_t * const button_F
+);
--- /dev/null
+This my software "klavirko-ui" is released under the 2-clause BSD license.
+
+It includes the appearances of some characters from the font unscii
+which is in the public domain
+https://github.com/viznut/unscii
+files: font*.*
+
+It used to contain files automatically created by e2studio.
+But because their copyright/license status was not clear I replaced
+all the files to avoid any problems.
--- /dev/null
+/*
+Copyright 2021, 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "klavirko-ui.h"
+#include "main.h"
+#include "aix.h"
+#include "lcd.h"
+#include "gui.h"
+#include "ctrl.h"
+#include "fs.h"
+
+volatile uint32_t main_timer = 0;
+
+inline void int_main_timer (void)
+{
+ ++main_timer;
+}
+
+// use only when interrupts already enabled
+void wait_ms (uint32_t const ms)
+{
+ uint32_t start;
+
+ start = main_timer;
+
+ while (((uint32_t)(main_timer - start)) < ms)
+ ;
+ return;
+}
+
+/* ! remember to keep reset_program.asm in agreement with main() definition */
+// int main (int argc, char ** argv)
+void main (void)
+{
+ /* * * SETUP IO * * */
+
+ //sustain DCDC power
+ DCDC__POM = 0;
+ DCDC__PMC = 0;
+ DCDC__PM = 0;
+ DCDC = 1;
+
+ /* * * SETUP CLOCK * * */
+
+ CMC = 0x00; // ignore external X1=8MHz
+ CKC = 0x00; // fclk = fmain; fmain=fih
+ CSC = 0xc0; // run only onchip HS.
+ //HIOTRM don't touch
+ HOCODIV = 0x00; //option byte / 1 : fih=32MHz, fhoco=64MHz
+
+ /* * * SETUP ALL SUBMODULES * * */
+
+ setup_lcd();
+ setup_aix();
+ setup_ctrl();
+ setup_gui();
+ setup_fs();
+
+ /* * * START * * */
+
+ EI();
+ init_lcd();
+ init_ctrl();
+ //init_gui();
+ init_fs();
+
+ /* * * PERFORM MAIN TASKS FOREVER * * */
+
+ while(1)
+ {
+ handle_aix();
+ handle_wave();
+ handle_gui();
+ handle_ctrl();
+ handle_debug();
+ }
+}
+
+uint8_t reverse_bits (uint8_t in) // reverse order of bits in a byte
+{
+ uint8_t out = 0;
+
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ out <<= 1;
+ in >>= 1;
+ out |= in & 0x01;
+ return out;
+}
+
+uint8_t make_dec_string ( // create decimal text representation of number
+ uint8_t * const string,
+ uint32_t value,
+ const uint8_t min_digits,
+ const uint8_t max_digits
+)
+{
+ int8_t i, j;
+ uint8_t text[10];
+ uint8_t digit;
+ uint8_t first_digit = 9;
+
+ for(i=9; i>=0; --i)
+ {
+ digit = value % 10;
+ value /= 10;
+
+ if (digit != 0)
+ first_digit = i;
+
+ text[i] = digit + '0';
+ }
+ if ((10 - min_digits) < first_digit)
+ first_digit = 10 - min_digits;
+ if ((10 - first_digit) > max_digits)
+ first_digit = 10 - max_digits;
+
+ for (i=first_digit, j=0; i<10; ++i, ++j)
+ string[j] = text[i];
+
+ return 10 - first_digit; // return actual number of digits
+}
+
+uint8_t make_hex_string ( // create hexadecimal text representation of number
+ uint8_t * const string,
+ uint32_t value,
+ const uint8_t min_digits,
+ const uint8_t max_digits,
+ const uint8_t uppercase
+)
+{
+ int8_t i, j;
+ uint8_t text[8];
+ uint8_t digit;
+ uint8_t first_digit = 7;
+
+ for(i=7; i>=0; --i)
+ {
+ digit = value & 0x0f;
+ value >>=4;
+
+ if (digit != 0)
+ first_digit = i;
+
+ if (digit < 10)
+ text[i] = digit + '0';
+ else if (uppercase)
+ text[i] = digit + 'A' - 10;
+ else
+ text[i] = digit + 'a' - 10;
+ }
+ if ((8 - min_digits) < first_digit)
+ first_digit = 8 - min_digits;
+ if ((8 - first_digit) > max_digits)
+ first_digit = 8 - max_digits;
+
+ for (i=first_digit, j=0; i<8; ++i, ++j)
+ string[j] = text[i];
+
+ return 8 - first_digit; // return actual number of digits
+}
--- /dev/null
+/*
+Copyright 2021, 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include "klavirko-ui.h"
+
+inline void int_main_timer (void) LOWTEXT; // handle timer every 1ms
+ void wait_ms (uint32_t const ms); // wait for defined number of milliseconds
+ /* ! remember to keep reset_program.asm in agreement with main() definition */
+ // int main (int argc, char ** argv);
+ void main (void);
+ uint8_t reverse_bits (uint8_t in); // reverse order of bits in a byte
+
+uint8_t make_dec_string ( // create decimal text representation of number
+ uint8_t * const string, // address where to create string
+ uint32_t value,
+ const uint8_t min_digits,
+ const uint8_t max_digits
+); // return actual number of digits
+uint8_t make_hex_string ( // create hexadecimal text representation of number
+ uint8_t * const string, // address where to create string
+ uint32_t value,
+ const uint8_t min_digits,
+ const uint8_t max_digits,
+ uint8_t uppercase // bool, 0xABCDEF, or 0xabcdef?
+); // return actual number of digits
+
+extern volatile uint32_t main_timer; // milliseconds since start
--- /dev/null
+# Copyright 2022 Balthasar Szczepański
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# My replacement for the makefile generated by e2studio
+
+# PATHS BELOW ARE SPECIFIC TO MY MACHINE,
+# UPDATE TO WHERE YOUR TOOLCHAIN IS LOCATED
+# Also it is assumed that rl78-elf-* tools are in PATH
+
+OBJCOPY := rl78-elf-objcopy
+LD := rl78-elf-ld
+SIZE := rl78-elf-size
+GCC := rl78-elf-gcc
+
+LIB += \
+--start-group \
+-loptm \
+-loptc \
+-lgcc \
+--end-group
+
+LIB_DIR += \
+-L"/usr/rl78-elf/rl78-elf/lib/g14" \
+-L"/usr/rl78-elf/lib/gcc/rl78-elf/4.9.2.201604-GNURL78/g14"
+
+OPTLIB_INC := -I "/usr/rl78-elf/rl78-elf/optlibinc"
+
+OPT_STACK := -Wstack-usage=312
+OPT_PLATFORM := -mg14
+
+OPT_D_C := -x c -nostdinc $(OPTLIB_INC) $(OPT_STACK) $(OPT_PLATFORM)
+OPT_O_C := -c $(OPT_D_C)
+# OPT_D_C := -x assembler-with-cpp -nostdinc $(OPTLIB_INC) $(OPT_STACK) $(OPT_PLATFORM)
+OPT_D_ASM := -x assembler -nostdinc $(OPTLIB_INC) $(OPT_STACK) $(OPT_PLATFORM)
+OPT_O_ASM := -c $(OPT_D_ASM)
+
+GCC_TOOL := gcc
+OPT_TOOL := -Wall
+LIB_M := -lm
+LIB_IL := -lIL
+RM := rm -rf
+
+HEX += \
+klavirko-ui.hex \
+klavirko-ui.mot
+
+OUT += \
+klavirko-ui.x
+
+OBJS += \
+interrupt_handlers.o \
+reset_program.o \
+vector_table.o \
+main.o \
+aix.o \
+lcd.o \
+gui.o \
+wave.o \
+ctrl.o \
+fs.o \
+debug.o
+
+CLEAN += \
+ $(OBJS) \
+ $(OUT) \
+ $(HEX) \
+ *.lst \
+ *.map \
+ *.x \
+ *.o \
+ *.d \
+ font.h \
+ sinus.h \
+ img2fnt \
+ sinus \
+ memory.ld \
+ size.tmp \
+
+
+all: $(OUT) $(HEX)
+ @echo 'complete'
+
+clean:
+ $(RM) $(CLEAN)
+
+
+klavirko-ui.hex: klavirko-ui.x
+ $(OBJCOPY) -O ihex klavirko-ui.x klavirko-ui.hex
+
+klavirko-ui.mot: klavirko-ui.x
+ $(OBJCOPY) -O srec klavirko-ui.x klavirko-ui.mot
+
+klavirko-ui.x: $(OBJS) memory.ld LinkerSubCommand.tmp
+ $(LD) -o klavirko-ui.x -T"memory.ld" @"LinkerSubCommand.tmp" -M=klavirko-ui.map $(LIB_DIR) $(LIB) -e_PowerON_Reset
+
+
+memory.ld: metalinker.pl memory_template.ld size.tmp LinkerSubCommand.tmp
+ ./metalinker.pl LinkerSubCommand.tmp size.tmp <memory_template.ld >memory.ld
+
+size.tmp: $(OBJS)
+ $(SIZE) $(OBJS) -A > size.tmp
+
+
+reset_program.o: reset_program.asm
+ $(GCC) -MM -MP -MF reset_program.o -MT reset_program.o -MT reset_program.d $(OPT_D_ASM) reset_program.asm
+ $(GCC) -Wa,-adlhn=reset_program.lst -o reset_program.o $(OPT_O_ASM) reset_program.asm
+
+interrupt_handlers.o: interrupt_handlers.c interrupt_handlers.h aix.h fs.h gui.h main.h ctrl.h
+ $(GCC) -MM -MP -MF interrupt_handlers.o -MT interrupt_handlers.o -MT interrupt_handlers.d $(OPT_D_C) interrupt_handlers.c
+ $(GCC) -Wa,-adlhn=interrupt_handlers.lst -o interrupt_handlers.o $(OPT_O_C) interrupt_handlers.c
+
+vector_table.o: vector_table.c interrupt_handlers.h aix.h ctrl.h gui.h lcd.h
+ $(GCC) -MM -MP -MF vector_table.o -MT vector_table.o -MT vector_table.d $(OPT_D_C) vector_table.c
+ $(GCC) -Wa,-adlhn=vector_table.lst -o vector_table.o $(OPT_O_C) vector_table.c
+
+main.o: main.c main.h aix.h lcd.h gui.h ctrl.h fs.h
+ $(GCC) -MM -MP -MF main.o -MT main.o -MT main.d $(OPT_D_C) main.c
+ $(GCC) -Wa,-adlhn=main.lst -o main.o $(OPT_O_C) main.c
+
+aix.o: aix.c aix.h debug.h wave.h gui.h
+ $(GCC) -MM -MP -MF aix.o -MT aix.o -MT aix.d $(OPT_D_C) aix.c
+ $(GCC) -Wa,-adlhn=aix.lst -o aix.o $(OPT_O_C) aix.c
+
+lcd.o: lcd.c lcd.h main.h debug.h font.h
+ $(GCC) -MM -MP -MF lcd.o -MT lcd.o -MT lcd.d $(OPT_D_C) lcd.c
+ $(GCC) -Wa,-adlhn=lcd.lst -o lcd.o $(OPT_O_C) lcd.c
+
+gui.o: gui.c gui.h debug.h wave.h lcd.h main.h fs.h ctrl.h
+ $(GCC) -MM -MP -MF gui.o -MT gui.o -MT gui.d $(OPT_D_C) gui.c
+ $(GCC) -Wa,-adlhn=gui.lst -o gui.o $(OPT_O_C) gui.c
+
+wave.o: wave.c wave.h aix.h debug.h ctrl.h sinus.h
+ $(GCC) -MM -MP -MF wave.o -MT wave.o -MT wave.d $(OPT_D_C) wave.c
+ $(GCC) -Wa,-adlhn=wave.lst -o wave.o $(OPT_O_C) wave.c
+
+ctrl.o: ctrl.c ctrl.h wave.h debug.h gui.h
+ $(GCC) -MM -MP -MF ctrl.o -MT ctrl.o -MT ctrl.d $(OPT_D_C) ctrl.c
+ $(GCC) -Wa,-adlhn=ctrl.lst -o ctrl.o $(OPT_O_C) ctrl.c
+
+fs.o: fs.c fs.h debug.h main.h gui.h wave.h
+ $(GCC) -MM -MP -MF fs.o -MT fs.o -MT fs.d $(OPT_D_C) fs.c
+ $(GCC) -Wa,-adlhn=fs.lst -o fs.o $(OPT_O_C) fs.c
+
+debug.o: debug.c debug.h main.h
+ $(GCC) -MM -MP -MF debug.o -MT debug.o -MT debug.d $(OPT_D_C) debug.c
+ $(GCC) -Wa,-adlhn=debug.lst -o debug.o $(OPT_O_C) debug.c
+
+
+sinus.h: sinus
+ ./sinus > sinus.h
+
+font.h: img2fnt font16.png font8.png
+ ./img2fnt FONT8 font8.png > font.h
+ ./img2fnt FONT16 font16.png >> font.h
+
+
+sinus: sinus.c
+ $(GCC_TOOL) $(OPT_TOOL) $(LIB_M) -o sinus sinus.c
+
+img2fnt: img2fnt.c
+ $(GCC_TOOL) $(OPT_TOOL) $(LIB_IL) -o img2fnt img2fnt.c
+
+
+.PHONY: all clean
+# What is secondary? Please explain.
+.SECONDARY:
--- /dev/null
+#initially autogenerated file.
+#now I'm taking it over manually.
+
+
+# Remove command components
+RM := rm -rf *.lst *.lis *.lpp *.map libgcc.a *.x *.o *.d
+
+# PATHS BELOW ARE SPECIFIC TO MY MACHINE,
+# UPDATE TO WHERE YOUR TOOLCHAIN IS LOCATED
+# Also it is assumed that rl78-elf-* tools are in PATH.
+
+# Compiler includes
+OPTLIB_INC := "/usr/rl78-elf/rl78-elf/optlibinc"
+
+# Linker includes
+LIB_INC1 := "/usr/rl78-elf/rl78-elf/lib/g14"
+LIB_INC2 := "/usr/rl78-elf/lib/gcc/rl78-elf/4.9.2.201604-GNURL78/g14"
+
+# All of the sources participating in the build are defined here
+
+OBJS += \
+./interrupt_handlers.o \
+./reset_program.o \
+./vector_table.o \
+./main.o \
+./aix.o \
+./lcd.o \
+./gui.o \
+./wave.o \
+./ctrl.o \
+./fs.o \
+./debug.o
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+LINKER_OUTPUT_OUTPUTS += \
+klavirko-ui.x \
+
+
+# All Target
+# Main-build Target
+all: klavirko-ui.mot klavirko-ui.hex
+ @echo 'Build complete.'
+
+# Tool invocations
+klavirko-ui.mot: $(LINKER_OUTPUT_OUTPUTS)
+ rl78-elf-objcopy -O srec $(LINKER_OUTPUT_OUTPUTS)"klavirko-ui.mot"
+
+klavirko-ui.hex: $(LINKER_OUTPUT_OUTPUTS)
+ rl78-elf-objcopy -O ihex $(LINKER_OUTPUT_OUTPUTS)"klavirko-ui.hex"
+
+klavirko-ui.x: $(OBJS) $(LIBRARY_GENERATOR_OUTPUTTYPE_OUTPUTS) $(ALL_ASMS) memory.ld LinkerSubCommand.tmp
+ rl78-elf-ld -o "klavirko-ui.x" -T"memory.ld" @"LinkerSubCommand.tmp" $(USER_OBJS) $(LIBS) $(LIBRARY_GENERATOR_OUTPUTTYPE_OUTPUTS) -M=klavirko-ui.map -L$(LIB_INC1) -L$(LIB_INC2) --start-group -loptm -loptc -lgcc --end-group -e_PowerON_Reset
+
+memory.ld: ./metalinker.pl ./memory_template.ld size.tmp LinkerSubCommand.tmp
+ ./metalinker.pl LinkerSubCommand.tmp size.tmp <memory_template.ld >memory.ld
+
+size.tmp: $(OBJS)
+ rl78-elf-size *.o -A > size.tmp
+
+
+# Build the objects
+
+# TODO: consider defining all repeating parameters as variable to avoid repetition.
+# hardware_setup.o: ./hardware_setup.c
+# rl78-elf-gcc -MM -MP -MF "hardware_setup.d" -MT"hardware_setup.o" -MT"hardware_setup.d" -x c -nostdinc -I$(OPTLIB_INC) -mg14 "$<"
+# rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I"$(OPTLIB_INC)" -mg14 -o "$(@:%.d=%.o)" "$<"
+
+interrupt_handlers.o: ./interrupt_handlers.c ./interrupt_handlers.h ./aix.h ./fs.h ./gui.h ./main.h ./ctrl.h
+ rl78-elf-gcc -MM -MP -MF "interrupt_handlers.d" -MT"interrupt_handlers.o" -MT"interrupt_handlers.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+reset_program.o: ./reset_program.asm
+ rl78-elf-gcc -MM -MP -MF "reset_program.d" -MT"reset_program.o" -MT"reset_program.d" -x assembler-with-cpp -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x assembler-with-cpp -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+main.o: ./main.c ./main.h ./aix.h ./lcd.h ./gui.h ./ctrl.h ./fs.h
+ rl78-elf-gcc -MM -MP -MF "main.d" -MT"main.o" -MT"main.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+aix.o: ./aix.c ./aix.h ./debug.h ./wave.h ./gui.h
+ rl78-elf-gcc -MM -MP -MF "aix.d" -MT"aix.o" -MT"aix.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+lcd.o: ./lcd.c ./lcd.h ./main.h ./debug.h font.h
+ rl78-elf-gcc -MM -MP -MF "lcd.d" -MT"lcd.o" -MT"lcd.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+gui.o: ./gui.c ./gui.h ./debug.h ./wave.h ./lcd.h ./main.h ./fs.h ./ctrl.h
+ rl78-elf-gcc -MM -MP -MF "gui.d" -MT"gui.o" -MT"gui.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+debug.o: ./debug.c ./debug.h ./main.h
+ rl78-elf-gcc -MM -MP -MF "debug.d" -MT"debug.o" -MT"debug.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+wave.o: ./wave.c ./wave.h ./aix.h ./debug.h ./ctrl.h sinus.h
+ rl78-elf-gcc -MM -MP -MF "wave.d" -MT"wave.o" -MT"wave.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+ctrl.o: ./ctrl.c ./ctrl.h ./wave.h ./debug.h ./gui.h
+ rl78-elf-gcc -MM -MP -MF "ctrl.d" -MT"ctrl.o" -MT"ctrl.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+fs.o: ./fs.c ./fs.h ./debug.h ./main.h ./gui.h ./wave.h
+ rl78-elf-gcc -MM -MP -MF "fs.d" -MT"fs.o" -MT"fs.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+vector_table.o: ./vector_table.c ./interrupt_handlers.h ./aix.h ./ctrl.h ./gui.h ./lcd.h
+ rl78-elf-gcc -MM -MP -MF "vector_table.d" -MT"vector_table.o" -MT"vector_table.d" -x c -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 "$<"
+ rl78-elf-gcc -c -x c -Wa,-adlhn="$(basename $(notdir $<)).lst" -nostdinc -I$(OPTLIB_INC) -Wstack-usage=312 -mg14 -o "$(@:%.d=%.o)" "$<"
+
+sinus.h: sinus
+ ./sinus > sinus.h
+
+sinus: ./sinus.c
+ gcc -lm -Wall -o sinus sinus.c
+
+font.h: img2fnt ./font16.png ./font8.png
+ ./img2fnt FONT8 ./font8.png > font.h
+ ./img2fnt FONT16 ./font16.png >> font.h
+
+img2fnt: ./img2fnt.c
+ gcc -lIL -Wall -o img2fnt img2fnt.c
+
+
+# Other Targets
+clean:
+ rm -rf klavirko-ui.mot klavirko-ui.hex font.h sinus.h img2fnt sinus memory.ld
+ $(RM)
+
+# What is phony? Please explain.
+.PHONY: all clean dependents
+.SECONDARY:
--- /dev/null
+/* memory.ld is generated from memory_template.ld by the meta linker script */
+/*
+my replacement for linker_script.gsi generated by e2studio.
+You will notice much similarity to the replaced thing.
+That's because these things must have such values to work correctly.
+Which makes the replacement kind of a pointless work as in the end
+almost the same thing comes out. But now it is mine.
+So, I believe this should not even be copyrightable,
+In case it is (after all, I did a creative trick here, however most of
+the actual creativity is in the meta linker script) then consider it
+copyrighted and released under the same license as the other files:
+*/
+/*
+Copyright 2021, 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+MEMORY
+{
+ VEC : ORIGIN = 0x00000, LENGTH = 0x4
+ IVEC : ORIGIN = 0x00004, LENGTH = 0xBC
+ OPT : ORIGIN = 0x000C0, LENGTH = 0x4
+ SEC_ID : ORIGIN = 0x000C4, LENGTH = 0xA
+ OCDSTAD : ORIGIN = 0x000CE, LENGTH = 0xA
+ ROM : ORIGIN = 0x000D8, LENGTH = 0x1FD28
+ OCDROM : ORIGIN = 0x1FE00, LENGTH = 0x200
+ /* 20000 - E0000 : unused */
+ /* F0000 - F2FFF : special stuff */
+ MIRROR : ORIGIN = 0xF3000, LENGTH = 0x8F00
+ RAM : ORIGIN = 0xFBF00, LENGTH = 0x4000
+ /* FFF00 - FFFFF : special stuff */
+}
+
+SECTIONS
+{
+ /* platform-specific stuff. must be here */
+ .vec 0x0 : AT (0x0)
+ {
+ KEEP(*(.vec))
+ } > VEC
+ .vects 0x4 : AT (0x4)
+ {
+ KEEP(*(.vects))
+ } > IVEC
+ .option_bytes 0xC0 : AT (0xC0)
+ {
+ KEEP(*(.option_bytes))
+ } > OPT
+ .security_id 0xC4 : AT (0xC4)
+ {
+ KEEP(*(.security_id))
+ } > SEC_ID
+
+ /* here, the actually interesting stuff starts */
+
+ /* low text - code with as low address as possible - reset, interrupt, etc. */
+ .lowtext 0xD8 : AT (0xD8)
+ {
+ *(.plt)
+ *(.lowtext)
+ . = ALIGN(2);
+ _mdata = .;
+ } > ROM
+
+ /* initial values for .data implicitly put here */
+
+ /* text - normal code */
+ .text (. + __romdatacopysize) :
+ {
+ /* here the meta linker will insert list of modules before mirror: */
+ /*OBJ_LOW_TEXT*/
+ } > ROM
+
+ /* here we interrupt the code, to insert data in the mirror area */
+
+ /* read-only data, which has to be in mirror */
+ .rodata MAX(., 0x3000) :
+ {
+ . = ALIGN(2);
+ *(.rodata)
+ *(.rodata.*)
+ _erodata = .;
+ ASSERT ((LOADADDR(.rodata) + SIZEOF(.rodata)) <= 0xbf00,"Error: no room left for .rodata");
+ } > ROM
+
+ /* resume with the code now */
+
+ /* text2 - normal code again - all modules which didn't get to text */
+ .text2 :
+ {
+ *(.text)
+ *(.text.*)
+ etext = .;
+ . = ALIGN(2);
+ } > ROM
+
+ PROVIDE (__rl78_abs__ = 0); /*?*/
+
+ /* .init, .fini, .got, could get here, however at this point not needed */
+
+ /* far read-only data which does not have to be in mirror */
+ .frodata :
+ {
+ *(.frodata)
+ } > ROM
+
+
+ /* end of flash, start of ram */
+
+ .data 0xFBF00 : AT (_mdata)
+ {
+ . = ALIGN(2);
+ _data = .;
+ *(.data)
+ *(.data.*)
+ . = ALIGN(2);
+ _edata = .;
+ } > RAM
+
+ PROVIDE (__romdatacopysize = SIZEOF(.data));
+
+ .bss :
+ {
+ . = ALIGN(2);
+ _bss = .;
+ *(.bss)
+ *(.bss.**)
+ . = ALIGN(2);
+ *(COMMON)
+ . = ALIGN(2);
+ _ebss = .;
+ _end = .;
+ } > RAM
+
+ PROVIDE (stack_size = 0x190);
+
+ .stack 0xFFEDC (NOLOAD) : AT (0xFFEDC)
+ {
+ _stack = .;
+ ASSERT ((_stack > (_end + stack_size)),"Error: Too much data - no room left for the stack");
+ } > RAM
+}
--- /dev/null
+#!/usr/bin/perl
+# linker script generator: META LINKER?
+#
+# Copyright 2021 Balthasar Szczepański
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+
+# modules which should always stay at low address
+use constant ALWAYS_LOW => {
+ # 'hardware_setup.o' => 1,
+ 'interrupt_handlers.o' => 1,
+ 'reset_program.o' => 1,
+ 'vector_table.o' => 1,
+};
+
+use constant ROM_START => 0x000D8;
+use constant MIRROR_START => 0x03000;
+use constant MIRROR_END => 0x0BEFF;
+
+my $listfile;
+my $sizefile;
+my $line;
+my @obj_low;
+my @obj_high;
+my @obj_check;
+my @obj_low_text;
+my @obj_high_text;
+my %data_size;
+my %rodata_size;
+my %text_size;
+my %lowtext_size;
+my $all_data = 0;
+my $all_rodata = 0;
+my $all_text = 0;
+my $low_text = 0;
+my $ptr;
+my $n_layout;
+my $max_layout;
+my $m_layout;
+
+if (@ARGV<2) {
+ print STDERR $0." objects_list_file objects_sizes_file\n";
+ exit;
+}
+
+# get list of modules & categorise
+
+unless (open ($listfile, "<", $ARGV[0])) {
+ print STDERR 'can\'t read '.$ARGV[0]."\n";
+ exit;
+}
+$line = <$listfile>;
+close ($listfile);
+
+while (length($line)>0) {
+ if ($line =~ /^\s*"([^"]*)"\s*/){
+ if (exists(ALWAYS_LOW->{$1})){
+ push(@obj_low, $1);
+ }
+ else {
+ push(@obj_check, $1);
+ }
+ $line = substr($line, $+[0]);
+ }
+ elsif ($line =~ /^\s*([^\s]*)\s*/){
+ if (exists(ALWAYS_LOW->{$1})){
+ push(@obj_low, $1);
+ }
+ else {
+ push(@obj_check, $1);
+ }
+ $line = substr($line, $+[0]);
+ }
+ else {
+ last;
+ }
+}
+
+$n_layout = @obj_check;
+$max_layout = (1 << $n_layout) - 1;
+
+# get module sizes
+
+unless (open ($sizefile, "<", $ARGV[1])) {
+ print STDERR 'can\'t read '.$ARGV[1]."\n";
+ exit;
+}
+{
+ my @words;
+ my $name;
+ while (defined($line = <$sizefile>)) {
+ $line =~ s/[\n]$//g;
+ @words = split (/\s*\t\s*/,$line);
+
+ if ($line =~ /^([^\s]+)\s*:/) {
+ $name = $1;
+ $data_size{$name} = 0;
+ $rodata_size{$name} = 0;
+ $text_size{$name} = 0;
+ $lowtext_size{$name} = 0;
+ }
+ # elsif ($line =~ /^\.((text)|(comment)|(debug_.*))\s+([0-9]+)/) {
+ # $text_size{$name} += int($5);
+ # }
+ elsif ($line =~ /^\.text\s+([0-9]+)/) {
+ $text_size{$name} += int($1);
+ }
+ elsif ($line =~ /^\.lowtext\s+([0-9]+)/) {
+ $lowtext_size{$name} += int($1);
+ }
+ elsif ($line =~ /^\.data\s+([0-9]+)/) {
+ $data_size{$name} += int($1);
+ }
+ elsif ($line =~ /^\.rodata\s+([0-9]+)/) {
+ $rodata_size{$name} += int($1);
+ }
+ }
+}
+close ($sizefile);
+
+# combine sizes
+
+foreach my $obj (@obj_low) {
+ $all_data += $data_size{$obj};
+ $all_rodata += $rodata_size{$obj};
+ $low_text += $lowtext_size{$obj} + $text_size{$obj};
+ $all_text += $lowtext_size{$obj} + $text_size{$obj};
+}
+foreach my $obj (@obj_check) {
+ $all_data += $data_size{$obj};
+ $all_rodata += $rodata_size{$obj};
+ $low_text += $lowtext_size{$obj};
+ $all_text += $lowtext_size{$obj} + $text_size{$obj};
+}
+
+# calculate base address
+
+$ptr = ROM_START;
+if ($ptr & 0x1) {
+ ++$ptr;
+}
+# print STDERR sprintf ("ROM START %05X\n",$ptr);
+$ptr += $all_data;
+if ($ptr & 0x1) {
+ ++$ptr;
+}
+# print STDERR sprintf ("TEXT START %05X\n",$ptr);
+$ptr += $low_text;
+# print STDERR sprintf ("TEXT 1 START %05X\n",$ptr);
+
+# find a valid layout
+
+$m_layout = find_layout();
+
+# my @ds = %data_size;
+# my @rs = %rodata_size;
+# my @ts = %text_size;
+
+# print STDERR "DATA @ds\nRODATA @rs\nTEXT @ts\n";
+
+# prepare replacement texts
+
+for(my $i=0; $i<$n_layout; ++$i) {
+ if ($m_layout & (1<<$i)) {
+ push(@obj_low, $obj_check[$i]);
+ }
+ else {
+ push(@obj_high, $obj_check[$i]);
+ }
+}
+
+# fill template with replacement texts
+
+foreach my $obj (@obj_low) {
+ push (@obj_low_text, $obj);
+ push (@obj_low_text, '(.text)');
+}
+foreach my $obj (@obj_high) {
+ push (@obj_high_text, $obj);
+ push (@obj_high_text, '(.text)');
+}
+while (defined($line = <STDIN>)) {
+ $line =~ s/\/\*OBJ_LOW\*\//@obj_low/;
+ $line =~ s/\/\*OBJ_HIGH\*\//@obj_high/;
+ $line =~ s/\/\*OBJ_ALL\*\//@obj_low @obj_high/;
+ $line =~ s/\/\*OBJ_LOW_TEXT\*\//@obj_low_text/;
+ $line =~ s/\/\*OBJ_HIGH_TEXT\*\//@obj_high_text/;
+ $line =~ s/\/\*OBJ_ALL_TEXT\*\//@obj_low_text @obj_high_text/;
+ print $line;
+}
+
+
+sub find_layout {
+ my $best_layout = $max_layout;
+ my $best_score = 0x100000;
+ my $layout;
+ my $score;
+
+ if (check_layout($max_layout) >= 0) {
+ return $max_layout;
+ }
+
+ for ($layout = $max_layout>>1; $layout != 0; $layout >>= 1) {
+ $score = check_layout($layout);
+ if ($score == 0) {
+ return $layout;
+ }
+ elsif (($score >0) && ($score < $best_score)) {
+ $best_layout = $layout;
+ $best_score = $score;
+ }
+ }
+
+ for ($layout = 0; $layout <= $max_layout; ++$layout) {
+ $score = check_layout($layout);
+ if ($score == 0) {
+ return $layout;
+ }
+ elsif (($score >0) && ($score < $best_score)) {
+ $best_layout = $layout;
+ $best_score = $score;
+ }
+ }
+
+ return $best_layout;
+}
+
+sub check_layout {
+ (my $layout) = @_;
+ my $add_text = 0;
+ my $pos;
+
+ for(my $i=0; $i<$n_layout; ++$i) {
+ if ($layout & (1<<$i)) {
+ $add_text += $text_size{$obj_check[$i]};
+ }
+ }
+
+ $pos = $ptr + $add_text;
+ if ($pos < MIRROR_START) {
+ return MIRROR_START - $pos;
+ }
+ $pos += $all_rodata;
+ if ($pos > (MIRROR_END + 1)) {
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+;; Copyright 2022 Balthasar Szczepański
+;;
+;; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+;;
+;; 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+;;
+;; 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+;; My replacement for the reset_program.asm generated by e2studio
+
+ .list
+ .section .lowtext
+
+ .extern _stack
+
+ .extern _mdata
+ .extern _data
+ .extern _edata
+
+ .extern _bss
+ .extern _ebss
+
+ .extern _main
+ .extern _exit ;; but why; isn't _exit defined here?
+
+ .global _PowerON_Reset
+ .short _PowerON_Reset
+
+_PowerON_Reset:
+
+;; step 1: set the stack pointer
+
+ movw sp, #_stack
+
+;; step 2: init .data
+init_data:
+
+ mov es, #0 ;; because we copy from 0xxxx to Fxxxx
+
+ movw de, #_mdata ;; .data in FLASH start
+ movw hl, #_data ;; .data in RAM start
+ movw bc, #_edata ;; .data in RAM end
+
+init_data_loop:
+ movw ax, es:[de] ;; get word from flash
+ movw [hl],ax ;; put word to ram
+
+ incw de ;; increment pointers to next word
+ incw de
+ incw hl
+ incw hl
+
+ movw ax, hl ;; prepare to compare
+ cmpw ax, bc ;; did we reach the end?
+ bnz $init_data_loop ;; if not: another iteration
+
+;; step 3: init .bss
+init_bss:
+
+ movw hl, #_bss ;; .bss in RAM start
+ movw bc, #_ebss ;; .bss in RAM end
+
+init_bss_loop:
+ movw ax, #0
+ movw [hl],ax ;; put 0 to ram
+
+ incw hl ;; increment pointer to next word
+ incw hl
+
+ movw ax, hl ;; prepare to compare
+ cmpw ax, bc ;; did we reach the end?
+ bnz $init_bss_loop ;; if not: another iteration
+
+;; step 4: call main()
+call_main:
+
+ movw ax, #0
+ ;;push ax
+ ;;push ax
+ ;;push ax
+
+ ;; removed pointless passing of argc, argv, envp
+ ;; redefined main as void main (void)
+
+ call !!_main
+
+;; step 5: main() has returned / exited for some reason:
+_exit:
+
+ ;;br $_exit ;; in this case, get stuck forever
+ br $_PowerON_Reset ;; in this case, restart from beginning
+
+ .end
+
\ No newline at end of file
--- /dev/null
+/* generator of .h file with sine wave */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+int main(int argc, char **argv)
+{
+ uint16_t i;
+ uint32_t j;
+
+ printf("//autogenerated by sinus.c\n");
+ printf("#define DEFAULT_SINE \\\n{");
+ for (i=0; i<256; ++i)
+ {
+ j = ((uint16_t)(16*(cos(i * M_PI / 128) + 1) * 255/2 + 0.5) - 128*16) & 0xffff;
+ printf("%s0x%04" PRIX32 "%s", ((i%8)==0)?" \\\n\t":" ", j,(i==255)?"":",");
+ }
+ printf (" \\\n}\n#define DEFAULT_SAMPLE \\\n{");
+ for (i=0; i<256; ++i)
+ {
+ j = ((uint16_t)((cos(i * M_PI / 128) + 1) * 255/2 + 0.5) - 128) & 0xff;
+ printf("%s0x%02" PRIX32 "%s", ((i%8)==0)?" \\\n\t":" ", j,(i==255)?"":",");
+ }
+ printf (" \\\n}\n");
+}
--- /dev/null
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interrupt_handlers.h"
+#include "aix.h"
+#include "ctrl.h"
+#include "gui.h"
+#include "lcd.h"
+
+extern void PowerON_Reset (void);
+
+const unsigned char Option_Bytes[] __attribute__ ((section (".option_bytes"))) = {
+ 0xef, // default
+ 0b01110111, // LV reset: 2.95V - 3.02V
+ 0b11111000, // HS fhoco=64Mhz, fih = 32MHz
+ 0x85 // default
+};
+
+const unsigned char Security_Id[] __attribute__ ((section (".security_id"))) = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const void *HardwareVectors[] __attribute__ ((section (".vec"))) = {
+ // Address 0x0
+ PowerON_Reset,
+ // Secure for Debugging
+ (void*)0xFFFF
+};
+
+const void *Vectors[] __attribute__ ((section (".vects"))) = {
+ FALLBACK_INT, // INT_SRO/INT_WDTI (0x4)
+ FALLBACK_INT, // INT_LVI (0x6)
+ FALLBACK_INT, // INT_P0 (0x8)
+ FALLBACK_INT, // INT_P1 (0xA)
+ FALLBACK_INT, // INT_P2 (0xC)
+ FALLBACK_INT, // INT_P3 (0xE)
+ FALLBACK_INT, // INT_P4 (0x10)
+ FALLBACK_INT, // INT_P5 (0x12)
+ FALLBACK_INT, // INT_CSI20/INT_IIC20/INT_ST2 (0x14)
+ FALLBACK_INT, // INT_CSI21/INT_IIC21/INT_SR2 (0x16)
+ FALLBACK_INT, // INT_SRE2 (0x18)
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ FALLBACK_INT, // INT_CSI00/INT_IIC00/INT_ST0 (0x1E)
+ int_aix_rx,///////INT_CSI01/INT_IIC01/INT_SR0 (0x20)
+ int_aix_err,//////INT_SRE0/INT_TM01H (0x22)
+ FALLBACK_INT, // INT_ST1 (0x24)
+ int_ctrl_rx,//////INT_CSI11/INT_IIC11/INT_SR1 (0x26)
+ int_ctrl_err,/////INT_SRE1/INT_TM03H (0x28)
+ FALLBACK_INT, // INT_IICA0 (0x2A)
+ FALLBACK_INT, // INT_TM00 (0x2C)
+ FALLBACK_INT, // INT_TM01 (0x2E)
+ FALLBACK_INT, // INT_TM02 (0x30)
+ FALLBACK_INT, // INT_TM03 (0x32)
+ INT_AD,///////////INT_AD (0x34)
+ FALLBACK_INT, // INT_RTC (0x36)
+ FALLBACK_INT, // INT_IT (0x38)
+ int_button_y,/////INT_KR (0x3A)
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ int_lcd_pwm,//////INT_TRJ0 (0x40)
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ FALLBACK_INT, // INT_P6 (0x4A)
+ (void*)0xFFFF, // Padding
+ int_jog,//////////INT_P8 (0x4E)
+ int_jog,//////////INT_P9 (0x50)
+ FALLBACK_INT, // INT_CMP0/INT_P10 (0x52)
+ FALLBACK_INT, // INT_CMP1/INT_P11 (0x54)
+ FALLBACK_INT, // INT_TRD0 (0x56)
+ FALLBACK_INT, // INT_TRD1 (0x58)
+ FALLBACK_INT, // INT_TRG (0x5A)
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ FALLBACK_INT, // INT_FL (0x62)
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ (void*)0xFFFF, // Padding
+ FALLBACK_INT, // INT_BRK_I (0x7E)
+};
--- /dev/null
+/* waveform & envelope */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "klavirko-ui.h"
+#include "wave.h"
+#include "aix.h"
+#include "debug.h"
+#include "ctrl.h"
+#include "sinus.h"
+
+const int16_t sine[N_SAMPLE] = DEFAULT_SINE;
+ int8_t sample[N_SAMPLE] = DEFAULT_SAMPLE;
+ uint32_t adsr_A = DEFAULT_A;
+ uint32_t adsr_D = DEFAULT_D;
+ uint32_t adsr_S = DEFAULT_S;
+ uint32_t adsr_R = DEFAULT_R;
+ uint16_t tuning = DEFAULT_TUNING;
+ int8_t transp = 0;
+ uint16_t max_tuning = DEFAULT_TUNING;
+ uint32_t main_clock = MAIN_CLOCK;
+ uint32_t clock_div = CLOCK_DIV;
+ uint32_t adsr_factor_a;
+ uint32_t adsr_factor_d;
+
+ uint8_t wave_changed = 0;
+ uint8_t adsr_changed = 0;
+ uint8_t wave_locked = 0;
+ uint8_t adsr_locked = 0;
+
+void set_timing (
+ const uint32_t clock,
+ const uint32_t div
+)
+{
+ main_clock = clock;
+ clock_div = div;
+
+ adsr_factor_a = clock * ADSR_FACTOR_A;
+ adsr_factor_d = clock * ADSR_FACTOR_D;
+
+ adsr_factor_a /= div;
+ adsr_factor_d /= div;
+
+ adsr_factor_a >>= ADSR_REDUCE_A;
+ adsr_factor_d >>= ADSR_REDUCE_D;
+}
+
+inline void set_max_tuning (const uint16_t max)
+{
+ max_tuning = max;
+ if (tuning > max)
+ {
+ tuning = max;
+ transp = 0;
+ ctrl_update_tuning();
+ }
+}
+
+inline void set_tuning (const uint16_t new)
+{
+ if (new <= max_tuning)
+ {
+ tuning = new;
+ ctrl_update_tuning();
+ }
+}
+
+inline void set_transp (const int8_t new)
+{
+ transp = new;
+ ctrl_update_tuning();
+}
+
+inline void update_wave (void)
+{
+ wave_changed = 1;
+}
+
+inline void update_adsr (void)
+{
+ adsr_changed = 1;
+}
+
+inline void lock_wave (void)
+{
+ wave_locked = 1;
+}
+
+inline void unlock_wave (void)
+{
+ wave_locked = 0;
+}
+
+inline void lock_adsr (void)
+{
+ adsr_locked = 1;
+}
+
+inline void unlock_adsr (void)
+{
+ adsr_locked = 0;
+}
+
+void calculate_adsr (void)
+{
+ uint32_t a, d, s, r;
+
+ a = aix_data[AIX_A] & ADSR_IN_MASK;
+ d = aix_data[AIX_D] & ADSR_IN_MASK;
+ s = aix_data[AIX_S] & ADSR_IN_MASK;
+ r = aix_data[AIX_R] & ADSR_IN_MASK;
+
+ adsr_S = (s<<22)|(s<<12)|(s<<2)|(s>>8); //spread 10 bits to 32
+ if (adsr_S < ADSR_FAKE_MIN)
+ {
+ s = ADSR_FAKE_MIN;
+ if (adsr_S < ADSR_MIN)
+ adsr_S = 0;
+ }
+ else
+ s = adsr_S;
+
+
+ a *= a * a;
+ d *= d * d;
+ r *= r * r;
+
+ // a >>= ADSR_REDUCE_1;
+ // d >>= ADSR_REDUCE_1;
+ // r >>= ADSR_REDUCE_1;
+
+ // a *= a;
+ // d *= d;
+ // r *= r;
+
+ a >>= ADSR_REDUCE_2A;
+ d >>= ADSR_REDUCE_2D;
+ r >>= ADSR_REDUCE_2D;
+
+ a *= adsr_factor_a;
+ d *= adsr_factor_d;
+ r *= adsr_factor_d;
+
+ a >>= ADSR_REDUCE_3A;
+ d >>= ADSR_REDUCE_3D;
+ r >>= ADSR_REDUCE_3D;
+
+ adsr_A = a ? (ADSR_MAX / a) : ADSR_MAX;
+ adsr_D = d ? ((ADSR_MAX - adsr_S) / d) : ADSR_MAX;
+ adsr_R = adsr_S ? (r ? (s / r) : ADSR_MAX) : adsr_D;
+}
+
+void calculate_wave (void)
+{
+ uint32_t v1, v2, v3, v4;
+ uint8_t t1, t2, t3, t4;
+ uint16_t a1, a2, a3, a4;
+ uint16_t b1, b2, b3, b4;
+ int16_t x;
+ int32_t acc;
+ uint16_t i;
+
+ v1 = aix_data[AIX_V1] & WAVE_IN_MASK;
+ v2 = aix_data[AIX_V2] & WAVE_IN_MASK;
+ v3 = aix_data[AIX_V3] & WAVE_IN_MASK;
+ v4 = aix_data[AIX_V4] & WAVE_IN_MASK;
+
+ v1 *= v1;
+ v2 *= v2;
+ v3 *= v3;
+ v4 *= v4;
+
+ v1 >>= WAVE_REDUCE_V1;
+ v2 >>= WAVE_REDUCE_V1;
+ v3 >>= WAVE_REDUCE_V1;
+ v4 >>= WAVE_REDUCE_V1;
+
+ v1 *= v1;
+ v2 *= v2;
+ v3 *= v3;
+ v4 *= v4;
+
+ v1 >>= WAVE_REDUCE_V2;
+ v2 >>= WAVE_REDUCE_V2;
+ v3 >>= WAVE_REDUCE_V2;
+ v4 >>= WAVE_REDUCE_V2;
+
+ v1 *= WAVE_XV1;
+ v2 *= WAVE_XV2;
+ v3 *= WAVE_XV3;
+ v4 *= WAVE_XV4;
+
+ v1 >>= WAVE_REDUCE_V3;
+ v2 >>= WAVE_REDUCE_V3;
+ v3 >>= WAVE_REDUCE_V3;
+ v4 >>= WAVE_REDUCE_V3;
+
+ t1 = aix_data[AIX_T1] >> WAVE_REDUCE_T;
+ t2 = aix_data[AIX_T2] >> WAVE_REDUCE_T;
+ t3 = aix_data[AIX_T3] >> WAVE_REDUCE_T;
+ t4 = aix_data[AIX_T4] >> WAVE_REDUCE_T;
+
+ if (aix_data[AIX_SW] == WAVE_SQUARE)
+ {
+ t1 = ((((uint16_t)t1)*SQWV_X)>>SQWV_RED)+SQWV_OFF;
+ for (i=0; i<256; ++i)
+ {
+ x = (i <= t1) ? SAMPLE_MAX : SAMPLE_MIN;
+ acc = (int32_t)(x * v1);
+ x = (((i<<1)-t2) & 0x80) ? SAMPLE_MIN : SAMPLE_MAX;
+ acc += (int32_t)(x * v2);
+ x = (((i*3)-t3) & 0x80) ? SAMPLE_MIN : SAMPLE_MAX;
+ acc += (int32_t)(x * v3);
+ x = (((i<<2)-t4) & 0x80) ? SAMPLE_MIN : SAMPLE_MAX;
+ acc += (int32_t)(x * v4);
+ acc >>= WAVE_REDUCE;
+ if (acc > 127)
+ acc = 127;
+ else if (acc < -128)
+ acc = -128;
+ sample[i] = (int8_t)acc;
+ }
+ }
+ else if (aix_data[AIX_SW] == WAVE_TRIANGLE)
+ {
+ if (t1!=0)
+ a1 = (SAMPLE_MAX - SAMPLE_MIN) / t1;
+ b1 = (SAMPLE_MAX - SAMPLE_MIN) / (N_SAMPLE - t1);
+ if (t2!=0)
+ a2 = (SAMPLE_MAX - SAMPLE_MIN) / t2;
+ b2 = (SAMPLE_MAX - SAMPLE_MIN) / (N_SAMPLE - t2);
+ if (t3!=0)
+ a3 = (SAMPLE_MAX - SAMPLE_MIN) / t3;
+ b3 = (SAMPLE_MAX - SAMPLE_MIN) / (N_SAMPLE - t3);
+ if (t4!=0)
+ a4 = (SAMPLE_MAX - SAMPLE_MIN) / t4;
+ b4 = (SAMPLE_MAX - SAMPLE_MIN) / (N_SAMPLE - t4);
+ for (i=0; i<256; ++i)
+ {
+ x = (i<t1) ? (SAMPLE_MIN + a1 * i) : (SAMPLE_MIN + b1 * (N_SAMPLE - i));
+ acc = (int32_t)(x * v1);
+ x = (i<<1)&0xff;
+ x = (x<t2) ? (SAMPLE_MIN + a2 * x) : (SAMPLE_MIN + b2 * (N_SAMPLE - x));
+ acc += (int32_t)(x * v2);
+ x = (i*3)&0xff;
+ x = (x<t3) ? (SAMPLE_MIN + a3 * x) : (SAMPLE_MIN + b3 * (N_SAMPLE - x));
+ acc += (int32_t)(x * v3);
+ x = (i<<2)&0xff;
+ x = (x<t4) ? (SAMPLE_MIN + a4 * x) : (SAMPLE_MIN + b4 * (N_SAMPLE - x));
+ acc += (int32_t)(x * v4);
+ acc >>= WAVE_REDUCE;
+ if (acc > 127)
+ acc = 127;
+ else if (acc < -128)
+ acc = -128;
+ sample[i] = (int8_t)acc;
+ }
+ }
+ else // sine
+ {
+ for (i=0; i<256; ++i)
+ {
+ x = sine[(i-t1)&0xff];
+ acc = (int32_t)(x * v1);
+ x = sine[((i<<1)-t2)&0xff];
+ acc += (int32_t)(x * v2);
+ x = sine[((i*3)-t3)&0xff];
+ acc += (int32_t)(x * v3);
+ x = sine[((i<<2)-t4)&0xff];
+ acc += (int32_t)(x * v4);
+ acc >>= WAVE_REDUCE;
+ if (acc > 127)
+ acc = 127;
+ else if (acc < -128)
+ acc = -128;
+ sample[i] = (int8_t)acc;
+ }
+ }
+}
+
+void handle_wave (void)
+{
+ if (adsr_changed && !adsr_locked)
+ {
+ adsr_changed = 0;
+ calculate_adsr();
+ gui_update_adsr();
+ ctrl_update_adsr();
+ }
+ if (wave_changed && !wave_locked)
+ {
+ wave_changed = 0;
+ calculate_wave();
+ gui_update_wave();
+ ctrl_update_wave();
+ }
+}
--- /dev/null
+/* waveform & envelope */
+/*
+Copyright 2021 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+
+// #include "sinus.h"
+
+#define N_SAMPLE 256
+
+#define WAVE_TRIANGLE 0x20 //top
+#define WAVE_SINE 0x30 //middle
+#define WAVE_SQUARE 0x10 //bottom
+
+#define SAMPLE_MAX 2032
+#define SAMPLE_MIN -2048
+
+#define DEFAULT_TUNING 4400
+#define MAIN_CLOCK 32000000
+#define CLOCK_DIV 720
+
+#define WAVE_IN_MASK 0x3FF
+//starting with 3ff - 10 bit
+//xx: ff801 - 20 bit
+#define WAVE_REDUCE_V1 4
+//ff80 - 16 bit
+//xx: ff004000 - 32 bit
+#define WAVE_REDUCE_V2 10
+//3fc010 - 22bit
+#define WAVE_XV1 642 //10/1
+#define WAVE_XV2 321 //10/2
+#define WAVE_XV3 214 //10/3
+#define WAVE_XV4 161 //10/4
+//9fdfa820 - 4fefd410 - 354a8d60 - 2817ca10 - 32 bit
+#define WAVE_REDUCE_V3 14
+//27f7e - 13fbf - 0d52a - 0a05f - 18 bit
+
+#define WAVE_REDUCE_T 2
+
+#define SQWV_X 207
+#define SQWV_OFF 25
+#define SQWV_RED 8
+
+#define WAVE_REDUCE 18
+
+// #define ADSR_IN_MASK 0x3FF
+// //starting with 3ff - 10 bit
+// //xx: ff801 - 20 bit
+// #define ADSR_REDUCE_1 4
+// //ff80 - 16 bit
+// //xx: ff004000 - 32 bit
+// #define ADSR_REDUCE_2A 13
+// #define ADSR_REDUCE_2D 17
+// //a: 1FE00 - 17bit; d: 1fe0 - 13 bit //OUTDATED
+// //xf: a: d00f2000, d: 81b30ac0 //OUTDATED
+// #define ADSR_REDUCE_3A 17
+// #define ADSR_REDUCE_3D 16
+// //a: 6807 (26631), d: 40d98 (265627) //OUTDATED
+
+#define ADSR_IN_MASK 0x3FF
+//10 bit
+//xxx: 30 bit
+#define ADSR_REDUCE_2A 11
+#define ADSR_REDUCE_2D 15
+//a: 19bit; d: 15 bit
+//xf: 32
+#define ADSR_REDUCE_3A 17
+#define ADSR_REDUCE_3D 13
+//a: 6807 (26631), d: 40d98 (265627) //OUTDATED
+
+#define ADSR_MAX 0xffffffff
+#define ADSR_MIN 0x02222222
+#define ADSR_FAKE_MIN 0x0aaaaaaa
+
+// max A 0.6s
+#define ADSR_FACTOR_A 77
+// #define ADSR_REDUCE_A 7
+#define ADSR_REDUCE_A 9
+#define DEFAULT_FACTOR_A \
+ (((MAIN_CLOCK * ADSR_FACTOR_A) / CLOCK_DIV) >> ADSR_REDUCE_A)
+
+// max D 6s
+#define ADSR_FACTOR_D 96
+// #define ADSR_REDUCE_D 4
+#define ADSR_REDUCE_D 6
+#define DEFAULT_FACTOR_D \
+ (((MAIN_CLOCK * ADSR_FACTOR_D) / CLOCK_DIV) >> ADSR_REDUCE_D)
+
+#define DEFAULT_A ADSR_MAX
+#define DEFAULT_D ADSR_MAX
+#define DEFAULT_S ADSR_MAX
+#define DEFAULT_R ADSR_MAX
+
+inline void update_adsr (void);
+inline void update_wave (void);
+inline void lock_wave (void);
+inline void unlock_wave (void);
+inline void lock_adsr (void);
+inline void unlock_adsr (void);
+
+ void calculate_adsr (void);
+ void calculate_wave (void);
+ void handle_wave (void);
+ void set_timing (
+ const uint32_t clock,
+ const uint32_t div
+);
+inline void set_max_tuning (const uint16_t max);
+inline void set_tuning (const uint16_t new);
+inline void set_transp (const int8_t new);
+
+extern int8_t sample[N_SAMPLE];
+extern uint32_t adsr_A;
+extern uint32_t adsr_D;
+extern uint32_t adsr_S;
+extern uint32_t adsr_R;
+extern uint16_t tuning;
+extern int8_t transp;
+extern uint8_t wave_locked;
+extern uint8_t adsr_locked;
\ No newline at end of file