From 54e94e64478c0c0d7c8027e11ae99adb9fe85b80 Mon Sep 17 00:00:00 2001 From: Trent Gill Date: Fri, 28 Jun 2024 20:36:00 -0700 Subject: [PATCH] system building & basic adc to dac passthrough --- Makefile | 2 + lib/casl.c | 4 +- lib/clock.c | 10 +- lib/events.c | 2 +- lib/ftrack.c | 3 + lib/ii.c | 520 ----------------- lib/ii.h | 41 -- lib/io.c | 5 +- lib/l_bootstrap.c | 173 ------ lib/l_bootstrap.h | 8 - lib/l_crowlib.c | 552 ------------------ lib/l_crowlib.h | 18 - lib/l_ii_mod.c | 288 ---------- lib/l_ii_mod.h | 22 - lib/lualink.c | 1259 ------------------------------------------ lib/lualink.h | 43 -- lib/metro.c | 4 +- lib/repl.c | 221 -------- lib/repl.h | 21 - ll/adc.c | 256 +++++++++ ll/adc.h | 14 + ll/adda.c | 189 ++----- ll/adda.h | 28 +- ll/ads131.c | 519 ----------------- ll/ads131.h | 122 ---- ll/dac108.c | 300 ++++++++++ ll/dac108.h | 20 + ll/dac8565.c | 14 +- ll/debug_usart.c | 38 +- ll/din.c | 36 ++ ll/din.h | 11 + ll/interrupts.h | 2 +- ll/lights.c | 87 +++ ll/lights.h | 10 + ll/status_led.c | 10 +- main.c | 119 ++-- stm32f7xx_hal_conf.h | 4 +- 37 files changed, 895 insertions(+), 4080 deletions(-) delete mode 100644 lib/ii.c delete mode 100644 lib/ii.h delete mode 100644 lib/l_bootstrap.c delete mode 100644 lib/l_bootstrap.h delete mode 100644 lib/l_crowlib.c delete mode 100644 lib/l_crowlib.h delete mode 100644 lib/l_ii_mod.c delete mode 100644 lib/l_ii_mod.h delete mode 100644 lib/lualink.c delete mode 100644 lib/lualink.h delete mode 100644 lib/repl.c delete mode 100644 lib/repl.h create mode 100644 ll/adc.c create mode 100644 ll/adc.h delete mode 100644 ll/ads131.c delete mode 100644 ll/ads131.h create mode 100644 ll/dac108.c create mode 100644 ll/dac108.h create mode 100644 ll/din.c create mode 100644 ll/din.h create mode 100644 ll/lights.c create mode 100644 ll/lights.h diff --git a/Makefile b/Makefile index 2711655f..730ee075 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ SRC = main.c \ system_stm32f7xx.c \ $(HALS)/stm32f7xx_hal.c \ $(HALS)/stm32f7xx_hal_cortex.c \ + $(HALS)/stm32f7xx_hal_adc.c \ $(HALS)/stm32f7xx_hal_rcc.c \ $(HALS)/stm32f7xx_hal_rcc_ex.c \ $(HALS)/stm32f7xx_hal_flash.c \ @@ -87,6 +88,7 @@ SRC = main.c \ $(HALS)/stm32f7xx_hal_pwr_ex.c \ $(HALS)/stm32f7xx_hal_rng.c \ $(HALS)/stm32f7xx_hal_spi.c \ + $(HALS)/stm32f7xx_hal_sai.c \ $(HALS)/stm32f7xx_hal_tim.c \ $(HALS)/stm32f7xx_hal_tim_ex.c \ $(HALS)/stm32f7xx_hal_uart.c \ diff --git a/lib/casl.c b/lib/casl.c index 140ae076..c775f2a2 100644 --- a/lib/casl.c +++ b/lib/casl.c @@ -6,7 +6,7 @@ #include "caw.h" // Caw_printf -#include "lualink.h" // L_queue_asl_done for raising a sequence-complete event +// #include "lualink.h" // L_queue_asl_done for raising a sequence-complete event // TODO // add sequins data type @@ -396,7 +396,7 @@ static void next_action( int index ) } else { stepup: if( !seq_up(self) ){ // To invalid. Jump up. return if nothing left to do - L_queue_asl_done(index); // trigger a lua event when sequence is complete + // L_queue_asl_done(index); // trigger a lua event when sequence is complete return; } } diff --git a/lib/clock.c b/lib/clock.c index 51cd177a..2d07eae6 100644 --- a/lib/clock.c +++ b/lib/clock.c @@ -4,7 +4,7 @@ #include #include -#include "lualink.h" +// #include "lualink.h" #include // HAL_GetTick #include "clock_ll.h" // linked list for clocks @@ -80,14 +80,14 @@ void clock_update(uint32_t time_now) sleep_next: if(sleep_head // list is not empty && sleep_head->wakeup < dtime_now){ // time to awaken - L_queue_clock_resume(sleep_head->coro_id); // event! + // L_queue_clock_resume(sleep_head->coro_id); // event! ll_insert_idle(ll_pop(&sleep_head)); // return to idle list goto sleep_next; // check the next sleeper too! } sync_next: if(sync_head // list is not empty && sync_head->wakeup < precise_beat_now){ // time to awaken - L_queue_clock_resume(sync_head->coro_id); // event! + // L_queue_clock_resume(sync_head->coro_id); // event! ll_insert_idle(ll_pop(&sync_head)); // return to idle list goto sync_next; // check the next syncer too! } @@ -139,14 +139,14 @@ void clock_update_reference_from(double beats, double beat_duration, clock_sourc void clock_start_from( clock_source_t source ) { if( clock_source == source ){ - L_queue_clock_start(); + // L_queue_clock_start(); } } void clock_stop_from( clock_source_t source ) { if( clock_source == source ){ - L_queue_clock_stop(); + // L_queue_clock_stop(); } } diff --git a/lib/events.c b/lib/events.c index b9b9acd7..d4822027 100644 --- a/lib/events.c +++ b/lib/events.c @@ -3,7 +3,7 @@ #include #include #include "events.h" -#include "lualink.h" +// #include "lualink.h" #include "caw.h" // Caw_send_luachunk diff --git a/lib/ftrack.c b/lib/ftrack.c index a1a61408..eaae7f9b 100644 --- a/lib/ftrack.c +++ b/lib/ftrack.c @@ -1,5 +1,6 @@ #include "ftrack.h" +/* #include "ll/adda.h" // ADDA_BLOCK_SIZE // time constant @@ -95,3 +96,5 @@ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) zc++; } } + +*/ diff --git a/lib/ii.c b/lib/ii.c deleted file mode 100644 index f39b68d4..00000000 --- a/lib/ii.c +++ /dev/null @@ -1,520 +0,0 @@ -#include "ii.h" - -#include -#include // memcpy -#include - -#include "../ll/i2c.h" -#include "../ll/i2c_pullups.h" -#include "../build/ii_c_layer.h" // GENERATED BY BUILD PROCESS -#include "lualink.h" -#include "wrQueue.h" -#include "wrMath.h" // lim_f -#include "caw.h" // Caw_send_luachunk - -// for follow getters -#include "io.h" -#include "slopes.h" - -#define II_MAX_BROADCAST_LEN 9 // cmd byte + 4*s16 args -#define II_MAX_RECEIVE_LEN 10 -#define II_QUEUE_LENGTH 16 -#define II_GET 128 // cmd >= are getter requests -#define II_TT_VOLT ((float)1638.3) -#define II_TT_iVOLT ((float)1.0/II_TT_VOLT) - -/////////////////////////// -// type declarations - -typedef struct{ - uint8_t address; - uint8_t length; - uint8_t query_length; // 0 for broadcast, >0 is return type byte size - uint8_t data[II_MAX_BROADCAST_LEN]; - uint8_t arg; // just carrying this through for the follower response - bool is_raw; -} ii_q_t; - - -//////////////////////////////////////// -// private declarations - -static void lead_callback( uint8_t address, uint8_t command, uint8_t* rx_data ); -static int follow_request( uint8_t* pdata ); -static int follow_action( uint8_t* pdata ); -static void error_action( int error_code ); - -static uint8_t type_size( ii_Type_t t ); -static float decode( uint8_t* data, ii_Type_t type ); -static uint8_t encode( uint8_t* dest, ii_Type_t type, float data ); -static float* decode_packet( float* decoded, uint8_t* data, const ii_Cmd_t* c, int is_following); -static uint8_t encode_packet( uint8_t* dest, const ii_Cmd_t* c, uint8_t cmd, float* data ); - - -//////////////////////////////// -// local variables - -queue_t* l_qix; -queue_t* f_qix; -ii_q_t l_iq[II_QUEUE_LENGTH]; -uint8_t f_iq[II_QUEUE_LENGTH][II_MAX_RECEIVE_LEN]; -uint8_t rx_arg = 0; // FIXME is there a better solution? -bool rx_is_raw = false; - - -//////////////////////// -// setup - -uint8_t ii_init( uint8_t address ) -{ - if( address != II_CROW - && address != II_CROW2 - && address != II_CROW3 - && address != II_CROW4 - ){ address = II_CROW; } // ensure a valid address - if( I2C_Init( (uint8_t)address - , &lead_callback - , &follow_action - , &follow_request - , &error_action - ) ){ printf("I2C Failed to Init\n"); } - - l_qix = queue_init( II_QUEUE_LENGTH ); - f_qix = queue_init( II_QUEUE_LENGTH ); - for( int i=0; iaddress = address; - const ii_Cmd_t* c = ii_find_command(address, cmd); - q->query_length = type_size( c->return_type ); - q->arg = data[0]; // save a copy of the first argument - q->length = encode_packet( q->data - , c - , cmd - , data - ); - ii_pickle( &q->address, q->data, &q->length ); - return 0; -} - -uint8_t ii_leader_enqueue_bytes( uint8_t address - , uint8_t* data - , uint8_t tx_len - , uint8_t rx_len - ) -{ - int ix = queue_enqueue( l_qix ); - if( ix < 0 ){ printf("queue full\n"); return 1; } - - ii_q_t* q = &l_iq[ix]; - - if( tx_len > II_MAX_BROADCAST_LEN ){ tx_len = II_MAX_BROADCAST_LEN; } - if( rx_len > II_MAX_RECEIVE_LEN ){ rx_len = II_MAX_RECEIVE_LEN; } - - q->is_raw = true; - q->address = address; - q->arg = tx_len > 1 ? data[1] : 0; - q->query_length = rx_len; - q->length = tx_len; - memcpy( q->data, data, tx_len ); - return 0; -} - -void ii_leader_process( void ) -{ - static bool retrying = false; // flag to monitor if this is a retry - - if( !I2C_is_ready() ){ return; } // I2C lib is busy - - int ix = queue_front(l_qix); - if( ix < 0 ){ return; } // queue is empty! - ii_q_t* q = &l_iq[ix]; - - int error = 0; - if( q->query_length ){ - rx_arg = q->arg; - rx_is_raw = q->is_raw; - if( (error = I2C_LeadRx( q->address - , q->data - , q->length - , q->query_length - )) ){ - if( error & 0x6 ){ error_action( 1 ); } - printf("leadRx failed %i\n",error); - goto retry; // attempt retry, or abandon - } - } else { - if( (error = I2C_LeadTx( q->address - , q->data - , q->length - )) ){ - if( error & 2 ){ error_action( 1 ); } - printf("leadTx failed %i\n",error); - goto retry; // attempt retry, or abandon - } - } - queue_dequeue(l_qix); // pop the value from queue as it was successfully used - return; - -retry: - if(retrying){ - retrying = false; - queue_dequeue(l_qix); // pop the value, abandoning this message - } else { - retrying = true; - // DON'T POP QUEUE. we'll try it next time - } - return; -} - - -/////////////////////////////////// -// follower: polling mode - -uint8_t* ii_processFollowRx( void ) -{ - int ix = queue_dequeue( f_qix ); - if( ix < 0 ){ return NULL; } // queue is empty! - return f_iq[ix]; -} - -// TODO localize queue -volatile int lead_has_data = 0; -uint8_t lead_data[I2C_MAX_CMD_BYTES]; -uint8_t* ii_processLeadRx( void ) -{ - uint8_t* pRetval = NULL; - if( lead_has_data ){ - pRetval = lead_data; - lead_has_data = 0; - } - return pRetval; // NULL for finished -} - - -//////////////////////////////////////////// -// LL driver callbacks - -static void lead_callback( uint8_t address, uint8_t command, uint8_t* rx_data ) -{ - if( !rx_is_raw ){ ii_unpickle( &address, &command, rx_data ); } - ii_Type_t return_type = ii_s32T; - const ii_Cmd_t* cmd = ii_find_command(address, command); - if( cmd != NULL ){ - return_type = cmd->return_type; - } - L_queue_ii_leadRx( address - , command - , decode( rx_data, return_type ) - , rx_arg - ); -} - -static int _two_step_request = 0; -static int follow_request( uint8_t* pdata ) -{ - // remember previous response to enable separate TX/RX pairs for query - // some devices (eg Teletype) do requests as separate messages - static float response = 0.0; - static const ii_Cmd_t* c; - - if( _two_step_request == 1 ){ - // response has already been set, so we just pass to encode - _two_step_request = 0; // unset 2-step - } else { - c = ii_find_command(ii_get_address(), *pdata); - float args[c->args]; - decode_packet( args, &pdata[1], c, 1 ); - switch( c->cmd ){ - case II_GET+3: // 'input' - response = IO_GetADC( (int)args[0] - 1 ); // i2c is 1-based - break; - case II_GET+4: // 'output' - response = S_get_state( (int)args[0] - 1 ); // i2c is 1-based - break; - default: // 'query' - // DANGER!! run the Lua callback directly! - // Not safe, but going via event queue would introduce *big* latency - response = L_handle_ii_followRxTx( c->cmd - , c->args - , args - ); - break; - } - } - return encode( pdata, c->return_type, response ); -} - -static int follow_action( uint8_t* pdata ) -{ - // some ii leaders (eg TT) do requests as an action with args followed by - // a request without args, which should use the prepared value - // here we capture GET cmds & prepare a val, and mark _two_step_request as true - if(ii_find_command(ii_get_address(), *pdata)->cmd >= II_GET){ - follow_request(pdata); // process as a request, ignore response - _two_step_request = 1; // mark as a 2-step request - return 0; - } - - int ix = queue_enqueue( f_qix ); - if( ix < 0 ){ - printf("ii_follow queue overflow\n"); - return 1; - } else { - memcpy( f_iq[ix], pdata, II_MAX_RECEIVE_LEN ); - L_queue_ii_followRx(); - } - return 0; -} - -// call this from the event system -void ii_process_dequeue_decode( void ) -{ - uint8_t* pdata = ii_processFollowRx(); - const ii_Cmd_t* c = ii_find_command(ii_get_address(), *pdata++); - float args[c->args]; - L_handle_ii_followRx_cont( c->cmd - , c->args - , decode_packet( args, pdata, c, 1 ) - ); -} - -static void error_action( int error_code ) -{ - switch( error_code ){ - case 0: // Ack Failed - // printf("I2C_ERROR_AF\n"); // means can't find device - // TODO make this a global variable which can be checked by user - // becomes a basic way to ask "was the message received" - break; - case 1: // Bus is busy. Could this also be ARLO? - if( I2C_GetPullups() ){ - // Caw_send_luachunk("ii: lines are low."); - // Caw_send_luachunk(" check ii devices are connected correctly."); - // Caw_send_luachunk(" check no ii devices are frozen."); - } else { - Caw_send_luachunk("ii: lines are low. try ii.pullup(true)"); - } - break; - default: // Unknown (ARLO?) - Caw_send_luachunk("ii: unknown error."); - printf("I2C_ERROR %i\n", error_code); - break; - } -} - - -///////////////////////////////////// -// ii Type Encode/Decode - -static uint8_t type_size( ii_Type_t t ) -{ - switch(t){ case ii_void: return 0; - case ii_u8: return 1; - case ii_s8: return 1; - case ii_u16: return 2; - case ii_s16: return 2; - case ii_s16V: return 2; - case ii_s16ms: return 2; - case ii_float: return 4; - case ii_s32T: return 4; - default: return 0; - } - return 0; -} - -static float decode( uint8_t* data, ii_Type_t type ) -{ - float val = 0; // return value default to zero - uint16_t u16 = 0; - switch( type ){ - case ii_u8: - val = (float)(*data++); - break; - case ii_s8: - val = (float)(*(int8_t*)data++); - break; - case ii_u16: - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - val = (float)u16; - break; - case ii_s16: - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - val = (float)*(int16_t*)&u16; - break; - case ii_s16V: - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - val = ((float)*(int16_t*)&u16)*II_TT_iVOLT; // Scale Teletype down to float - break; - case ii_s16ms: - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - val = (float)*(int16_t*)&u16/1000.0; - break; - case ii_float: - val = *(float*)data; - break; - case ii_s32T: - // seconds: signed 16 - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - val = (float)*(int16_t*)&u16; - // subsecond: signed 16 V - u16 = ((uint16_t)*data++)<<8; - u16 |= *data++; - // combine - val += ((float)*(int16_t*)&u16)*II_TT_iVOLT; - break; - default: printf("ii_decode unmatched\n"); break; - } - return val; -} - -static uint8_t encode( uint8_t* dest, ii_Type_t type, float data ) -{ - uint8_t len = 0; - uint8_t* d = dest; - - uint16_t u16; int16_t s16; - switch( type ){ - case ii_u8: d[len++] = (uint8_t)lim_f(data,0.0,255.0); - break; - case ii_s8: d[len++] = (int8_t)lim_f(data,-128.0,127.0); - break; - case ii_u16: - // clamp range to 16bit - u16 = (uint16_t)lim_f(data, 0.0, 65535.0); - d[len++] = (uint8_t)(u16>>8); // High byte first - d[len++] = (uint8_t)(u16 & 0x00FF); // Low byte - break; - case ii_s16V: - data *= II_TT_VOLT; // Scale float up to Teletype - // FLOWS THROUGH - case ii_s16: - s16 = (int16_t)lim_f(data, -32768.0, 32767.0); - u16 = *(uint16_t*)&s16; - d[len++] = (uint8_t)(u16>>8); // High byte first - d[len++] = (uint8_t)(u16 & 0x00FF); // Low byte - break; - case ii_s16ms: - data *= 1000.0; - // as ii_s16 - s16 = (int16_t)lim_f(data, -32768.0, 32767.0); - u16 = *(uint16_t*)&s16; - d[len++] = (uint8_t)(u16>>8); // High byte first - d[len++] = (uint8_t)(u16 & 0x00FF); // Low byte - break; - case ii_float: - memcpy( &(d[len]), &data, 4 ); - len += 4; - break; - case ii_s32T:{ - int iTime = (int)data; - float subTime = data - (float)iTime; - if( iTime < -32768 ){ - iTime = -32768; subTime = 0.0; - } else if( iTime > 32767 ){ - iTime = 32767; subTime = 0.0; - } - // signed 16 - s16 = (int16_t)iTime; - u16 = *(uint16_t*)&s16; - d[len++] = (uint8_t)(u16>>8); // High byte first - d[len++] = (uint8_t)(u16 & 0x00FF); // Low byte - // signed 16 V - subTime *= II_TT_VOLT; // Scale float up to Teletype - s16 = (int16_t)subTime; - u16 = *(uint16_t*)&s16; - d[len++] = (uint8_t)(u16>>8); // High byte first - d[len++] = (uint8_t)(u16 & 0x00FF); // Low byte - break;} - default: printf("no retval found\n"); return 0; - // FIXME: should this really print directly? or pass to caller? - } - return len; -} - -static float* decode_packet( float* decoded - , uint8_t* data - , const ii_Cmd_t* c - , int is_following - ) -{ - float* d = decoded; - if( is_following ){ - int len = 0; - for( int i=0; i<(c->args); i++ ){ - *d++ = decode( &data[len], c->argtype[i] ); - len += type_size( c->argtype[i] ); - } - } else { - *d = decode( data, c->return_type ); - } - return decoded; -} - -static uint8_t encode_packet( uint8_t* dest - , const ii_Cmd_t* c - , uint8_t cmd - , float* data - ) -{ - uint8_t len = 0; - dest[len++] = cmd; // first byte is command - for( int i=0; i<(c->args); i++ ){ - len += encode( &dest[len], c->argtype[i], *data++ ); - } - return len; -} diff --git a/lib/ii.h b/lib/ii.h deleted file mode 100644 index e0c651f1..00000000 --- a/lib/ii.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -typedef enum{ II_CROW = 0x01 - , II_CROW2 = 0x02 - , II_CROW3 = 0x03 - , II_CROW4 = 0x04 -} ii_ADDR_t; - - -///////////////////// -// setup -uint8_t ii_init( uint8_t address ); -void ii_deinit( void ); - -void ii_set_pullups( uint8_t state ); - -uint8_t ii_get_address( void ); -void ii_set_address( uint8_t index ); - - -////////////////////////// -// help (autogenerated) -const char* ii_list_modules( void ); -const char* ii_list_cmds( uint8_t address ); - - -///////////////////////// -uint8_t ii_leader_enqueue( uint8_t address, uint8_t cmd, float* data ); -uint8_t ii_leader_enqueue_bytes( uint8_t address , uint8_t* data , uint8_t tx_len, uint8_t rx_len ); -void ii_leader_process( void ); // call from event loop - - -/////////////////////////// -// reception dequeue -uint8_t* ii_processFollowRx( void ); -uint8_t* ii_processLeadRx( void ); - -// decoded -void ii_process_dequeue_decode( void ); diff --git a/lib/io.c b/lib/io.c index 4167bce7..9234e77d 100644 --- a/lib/io.c +++ b/lib/io.c @@ -11,12 +11,13 @@ #include "caw.h" #include "casl.h" -#include "lualink.h" // L_handle_in_stream (pass this in as ptr?) +// #include "lualink.h" // L_handle_in_stream (pass this in as ptr?) #define IN_CHANNELS ADDA_ADC_CHAN_COUNT static void public_update( void ); +/* void IO_Init( int adc_timer_ix ) { // hardware layer @@ -142,3 +143,5 @@ static void public_update( void ) chan = (chan + 1) % 6; } } + +*/ diff --git a/lib/l_bootstrap.c b/lib/l_bootstrap.c deleted file mode 100644 index 6db08482..00000000 --- a/lib/l_bootstrap.c +++ /dev/null @@ -1,173 +0,0 @@ -#include "l_bootstrap.h" - -#include -#include - -#include "l_crowlib.h" - -// Lua libs wrapped in C-headers -#include "build/crowlib.h" -#include "build/asl.h" -#include "build/asllib.h" -#include "build/clock.h" -#include "build/metro.h" -#include "build/public.h" -#include "build/input.h" -#include "build/output.h" -#include "build/ii.h" -// #include "build/iihelp.h" // generated lua stub for loading i2c modules -#include "build/calibrate.h" -#include "build/sequins.h" -#include "build/quote.h" -#include "build/timeline.h" -#include "build/hotswap.h" - -// #include "build/ii_lualink.h" // generated C header for linking to lua - -struct lua_lib_locator{ - const char* name; - const unsigned char* addr_of_luacode; - const bool stripped; - const unsigned int len; -}; - -static int _open_lib( lua_State *L, const struct lua_lib_locator* lib, const char* name ); -static void lua_full_gc(lua_State* L); - -// mark the 3rd arg 'false' if you need to debug that library -const struct lua_lib_locator Lua_libs[] = - { { "lua_crowlib" , build_crowlib_lc , true, build_crowlib_lc_len} - , { "lua_asl" , build_asl_lc , true, build_asl_lc_len} - , { "lua_asllib" , build_asllib_lc , true, build_asllib_lc_len} - , { "lua_clock" , build_clock_lc , true, build_clock_lc_len} - , { "lua_metro" , build_metro_lc , true, build_metro_lc_len} - , { "lua_input" , build_input_lc , true, build_input_lc_len} - , { "lua_output" , build_output_lc , true, build_output_lc_len} - , { "lua_public" , build_public_lc , true, build_public_lc_len} - , { "lua_ii" , build_ii_lc , true, build_ii_lc_len} - // , { "build_iihelp" , build_iihelp_lc , true, build_iihelp_lc_len} - , { "lua_calibrate" , build_calibrate_lc , true, build_calibrate_lc_len} - , { "lua_sequins" , build_sequins_lc , true, build_sequins_lc_len} - , { "lua_quote" , build_quote_lc , true, build_quote_lc_len} - , { "lua_timeline" , build_timeline_lc , true, build_timeline_lc_len} - , { "lua_hotswap" , build_hotswap_lc , true, build_hotswap_lc_len} - , { NULL , NULL , true, 0} - }; - - -void l_bootstrap_init(lua_State* L){ - // collectgarbage('setpause', 55) - lua_gc(L, LUA_GCSETPAUSE, 55); - lua_gc(L, LUA_GCSETSTEPMUL, 260); - - // dofile just calls c_dofile - lua_getglobal(L, "c_dofile"); - lua_setglobal(L, "dofile"); - - // crowlib.lua now only contains our print() definition - // _c = dofile('lua/crowlib.lua') - lua_pushliteral(L, "lua/crowlib.lua"); - l_bootstrap_dofile(L); // hotrod without l_call - lua_settop(L, 0); - - // _c = {} - lua_newtable(L); - lua_setglobal(L, "_c"); - - // crow = _c - lua_getglobal(L, "_c"); - lua_setglobal(L, "crow"); - - // crowlib C extensions - l_crowlib_init(L); - - // track all user-created globals - luaL_dostring(L, - "_user={}\n" - "local function trace(t,k,v)\n" - "_user[k]=true\n" - "rawset(t,k,v)\n" - "end\n" - "setmetatable(_G,{ __newindex = trace })\n" - ); - - // perform two full garbage collection cycles for full cleanup - lua_full_gc(L); -} - - -int l_bootstrap_dofile(lua_State* L) -{ - const char* l_name = luaL_checkstring(L, 1); - int l_len = strlen(l_name); - if(l_len > 32) printf("FIXME bootstrap: filepath >32bytes!\n\r"); - - // simple C version of "luapath_to_cpath" - // l_name is a lua native path: "lua/asl.lua" - char cname[32]; // 32bytes is more than enough for any path - int p=0; // pointer into cname - for(int i=0; i - -#include "l_bootstrap.h" // l_bootstrap_dofile -#include "l_ii_mod.h" // l_ii_mod_preload -#include "../ll/random.h" // Random_Get() -#include "lib/ii.h" // ii_*() -#include "lib/ashapes.h" // AShaper_get_state -#include "lib/caw.h" // Caw_printf() -#include "lib/io.h" // IO_GetADC() - -#define L_CL_MIDDLEC (261.63f) -#define L_CL_MIDDLEC_INV (1.0f/L_CL_MIDDLEC) -#define L_CL_JIVOLT (1.0f/logf(2.f)) - - -static int _ii_follow_reset( lua_State* L ); -static int _random_arity_n( lua_State* L ); -static int _tell_get_out( lua_State* L ); -static int _tell_get_cv( lua_State* L ); -static int _lua_void_function( lua_State* L ); -static int _delay( lua_State* L ); - -// function() end -// useful as a do-nothing callback -static int _lua_void_function( lua_State* L ){ - lua_settop(L, 0); - return 0; -} - -static void _load_lib(lua_State* L, char* filename, char* luaname){ - lua_pushfstring(L, "lua/%s.lua", filename); - l_bootstrap_dofile(L); - lua_setglobal(L, luaname); - lua_settop(L, 0); -} - -// called after crowlib lua file is loaded -// here we add any additional globals and such -void l_crowlib_init(lua_State* L){ - - //////// create a nop function - lua_pushcfunction(L, _lua_void_function); - lua_setglobal(L, "nop_fn"); - - //////// load all libraries - _load_lib(L, "input", "Input"); - _load_lib(L, "output", "Output"); - _load_lib(L, "asl", "asl"); - _load_lib(L, "asllib", "asllib"); - _load_lib(L, "metro", "metro"); - - // load C funcs into lua env first - l_ii_mod_preload(L); - _load_lib(L, "ii", "ii"); - - _load_lib(L, "calibrate", "cal"); - _load_lib(L, "public", "public"); - _load_lib(L, "clock", "clock"); - _load_lib(L, "sequins", "sequins"); - _load_lib(L, "quote", "quote"); - _load_lib(L, "timeline", "timeline"); - _load_lib(L, "hotswap", "hotswap"); - - - //////// crow.reset - lua_getglobal(L, "crow"); // @1 - lua_pushcfunction(L, l_crowlib_crow_reset); - lua_setfield(L, 1, "reset"); - lua_settop(L, 0); - - - //////// tell - // C.tell = tell - lua_getglobal(L, "crow"); // @1 - lua_getglobal(L, "tell"); // @2 - lua_setfield(L, 1, "tell"); - lua_settop(L, 0); - - - //////// get_out & get_cv - lua_pushcfunction(L, _tell_get_out); - lua_setglobal(L, "get_out"); - lua_pushcfunction(L, _tell_get_cv); - lua_setglobal(L, "get_cv"); - lua_settop(L, 0); - - - //////// input - - // -- Input - // input = {1,2} - // for chan = 1, #input do - // input[chan] = Input.new( chan ) - // end - lua_createtable(L, 2, 0); // 2 array elements - lua_setglobal(L, "input"); // -> @0 - - lua_getglobal(L, "input"); // @1 - for(int i=1; i<=2; i++){ - lua_getglobal(L, "Input"); // @2 - lua_getfield(L, 2, "new"); // Output.new @3 - lua_pushinteger(L, i); // push the key - lua_call(L, 1, 1); // Output.new(chan) -> replace key with value -> @3 - lua_pushinteger(L, i); // push the key - lua_rotate(L, -2, 1); // swap top 2 elements - lua_settable(L, 1); // output[chan] = result - lua_settop(L, 1); // discard everything except _G.output - } - lua_settop(L, 0); - - - //////// output (asl) - - // -- Output - // output = {1,2,3,4} - // for chan = 1, #output do - // output[chan] = Output.new( chan ) - // end - lua_createtable(L, 4, 0); // 4 array elements - lua_setglobal(L, "output"); // -> @0 - - lua_getglobal(L, "output"); // @1 - for(int i=1; i<=4; i++){ - lua_getglobal(L, "Output"); // @2 - lua_getfield(L, 2, "new"); // Output.new @3 - lua_pushinteger(L, i); // push the key - lua_call(L, 1, 1); // Output.new(chan) -> replace key with value -> @3 - lua_pushinteger(L, i); // push the key - lua_rotate(L, -2, 1); // swap top 2 elements - lua_settable(L, 1); // output[chan] = result - lua_settop(L, 1); // discard everything except _G.output - } - lua_settop(L, 0); - - - // LL_get_state = get_state - lua_getglobal(L, "get_state"); - lua_setglobal(L, "LL_get_state"); - lua_settop(L, 0); - - - //////// ii follower default actions - - // install the reset function - lua_pushcfunction(L, _ii_follow_reset); - lua_setglobal(L, "ii_follow_reset"); - - // call it to reset immediately - lua_getglobal(L, "ii_follow_reset"); - lua_call(L, 0, 0); - lua_settop(L, 0); - - - //////// ii.pullup(true) - ii_set_pullups(1); - - - //////// RANDOM - - // hook existing math.random into math.srandom - lua_getglobal(L, "math"); // 1 - lua_getfield(L, 1, "random"); // 2 - lua_setfield(L, 1, "srandom"); - lua_settop(L, 1); // abandon anything above _G.math - // _G.math is still at stack position 1 - lua_getfield(L, 1, "randomseed"); - lua_setfield(L, 1, "srandomseed"); - lua_settop(L, 0); - - // set math.random to the c-func for true random - lua_getglobal(L, "math"); - lua_pushcfunction(L, _random_arity_n); - lua_setfield(L, -2, "random"); - lua_settop(L, 0); - - - //////// DELAY - // creates a closure, so this is just way easier - luaL_dostring(L,"function delay(action, time, repeats)\n" - "local r = repeats or 0\n" - "return clock.run(function()\n" - "for i=1,1+r do\n" - "clock.sleep(time)\n" - "action(i)\n" - "end\n" - "end)\n" - "end\n"); - - l_crowlib_emptyinit(L); -} - -void l_crowlib_emptyinit(lua_State* L){ - //////// set init() to a NOP - lua_getglobal(L, "nop_fn"); - lua_setglobal(L, "init"); -} - - -int l_crowlib_crow_reset( lua_State* L ){ - printf("crow.reset()\n\r"); - - lua_getglobal(L, "input"); // @1 - for(int i=1; i<=2; i++){ - lua_settop(L, 1); // _G.input is TOS @1 - lua_pushinteger(L, i); // @2 - lua_gettable(L, 1); // replace @2 with: input[n] - - // input[n].mode = 'none' - lua_pushstring(L, "none"); // @3 - lua_setfield(L, 2, "mode"); // pops 'none' -> @2 - - // input[n].reset_events(input[n]) -- aka void method call - lua_getfield(L, 2, "reset_events"); // @3 - lua_pushvalue(L, 2); // @4 copy of input[n] - lua_call(L, 1, 0); - } - lua_settop(L, 0); - - lua_getglobal(L, "output"); // @1 - for(int i=1; i<=4; i++){ - lua_settop(L, 1); // _G.output is TOS @1 - lua_pushinteger(L, i); // @2 - lua_gettable(L, 1); // replace @2 with: output[n] - - // output[n].slew = 0 - lua_pushnumber(L, 0.0); // @3 - lua_setfield(L, 2, "slew"); // pops 'slew' -> @2 - // output[n].volts = 0 - lua_pushnumber(L, 0.0); // @3 - lua_setfield(L, 2, "volts"); // pops 'volts' -> @2 - // output[n].scale('none') - lua_getfield(L, 2, "scale"); - lua_pushstring(L, "none"); - lua_call(L, 1, 0); - // output[n].done = function() end - lua_getglobal(L, "nop_fn"); // @3 - lua_setfield(L, 2, "done"); // pops nop_fn -> @2 - // output[n]:clock('none') - lua_getfield(L, 2, "clock"); // @3 - lua_pushvalue(L, 2); // @4 copy of output[n] - lua_pushstring(L, "none"); - lua_call(L, 2, 0); - - // output[n].reset_events(output[n]) -- aka void method call - lua_getfield(L, 2, "reset_events"); // @3 - lua_pushvalue(L, 2); // @4 copy of output[n] - lua_call(L, 1, 0); - } - lua_settop(L, 0); - - // ii.reset_events(ii.self) - lua_getglobal(L, "ii"); // @1 - lua_getfield(L, 1, "reset_events"); // @2 - lua_getfield(L, 1, "self"); // @3 - lua_call(L, 1, 0); - lua_settop(L, 0); - - // ii_follow_reset() -- resets forwarding to output libs - lua_getglobal(L, "ii_follow_reset"); - lua_call(L, 0, 0); - lua_settop(L, 0); - - // metro.free_all() - lua_getglobal(L, "metro"); // @1 - lua_getfield(L, 1, "free_all"); - lua_call(L, 0, 0); - lua_settop(L, 0); - - // if public then public.clear() end - lua_getglobal(L, "public"); // @1 - if(!lua_isnil(L, 1)){ // if public is not nil - lua_getfield(L, 1, "clear"); - lua_call(L, 0, 0); - } - lua_settop(L, 0); - - // clock.cleanup() - lua_getglobal(L, "clock"); // @1 - lua_getfield(L, 1, "cleanup"); - lua_call(L, 0, 0); - lua_settop(L, 0); - - // hotswap.cleanup() - lua_getglobal(L, "hotswap"); // @1 - lua_getfield(L, 1, "cleanup"); - lua_call(L, 0, 0); - lua_settop(L, 0); - - return 0; -} - - -/////// static declarations - -// Just Intonation calculators -// included in lualink.c as global lua functions - -static int justvolts(lua_State* L, float mul); - -int l_crowlib_justvolts(lua_State* L){ - return justvolts(L, 1.f); -} - -int l_crowlib_just12(lua_State *L){ - return justvolts(L, 12.f); -} - -int l_crowlib_hztovolts(lua_State *L){ - // assume numbers, not tables - float retval = 0.f; - switch(lua_gettop(L)){ - case 1: // use default middleC reference - // note we - retval = log2f(luaL_checknumber(L, 1) * L_CL_MIDDLEC_INV); - break; - case 2: // use provided reference - retval = log2f(luaL_checknumber(L, 1)/luaL_checknumber(L, 2)); - break; - default: - lua_pushliteral(L, "need 1 or 2 args"); - lua_error(L); - break; - } - lua_settop(L, 0); - lua_pushnumber(L, retval); - return 1; -} - -static int justvolts(lua_State* L, float mul){ - // apply optional offset - float offset = 0.f; - switch(lua_gettop(L)){ - case 1: break; - case 2: {offset = log2f(luaL_checknumber(L, 2))*mul;} break; - default: - lua_pushliteral(L, "need 1 or 2 args"); - lua_error(L); - break; - } - - // now do the conversion - int nresults = 0; - switch(lua_type(L, 1)){ - case LUA_TNUMBER:{ - float result = log2f(lua_tonumber(L, 1))*mul + offset; - lua_settop(L, 0); - lua_pushnumber(L, result); - nresults = 1; - break;} - case LUA_TTABLE:{ - // get length of table to convert - lua_len(L, 1); - int telems = lua_tonumber(L, -1); - lua_pop(L, 1); - - // build the new table in C (a copy) - float newtab[telems+1]; // bottom element is unused - for(int i=1; i<=telems; i++){ - lua_geti(L, 1, i); - newtab[i] = log2f(luaL_checknumber(L, -1))*mul + offset; - lua_pop(L, 1); // pops the number from the stack - } - - // push the C table into the lua table - lua_settop(L, 0); - lua_createtable(L, telems, 0); - for(int i=1; i<=telems; i++){ - lua_pushnumber(L, newtab[i]); - lua_seti(L, 1, i); - } - nresults = 1; - break;} - default: - lua_pushliteral(L, "unknown voltage type"); - lua_error(L); - break; - } - return nresults; -} - -/// true random - -static int _random_arity_n( lua_State* L ) -{ - int nargs = lua_gettop(L); - switch(nargs){ - case 0:{ - float r = Random_Float(); - lua_settop(L, 0); - lua_pushnumber(L, r); - break;} - case 1:{ - int r = Random_Int(1, luaL_checknumber(L, 1)); - lua_settop(L, 0); - lua_pushinteger(L, r); - break;} - default:{ - int r = Random_Int(luaL_checknumber(L, 1) - ,luaL_checknumber(L, 2)); - lua_settop(L, 0); - lua_pushinteger(L, r); - break;} - } - return 1; -} - -// ii follower default actions - -// function(chan,val) output[chan].volts = val end -static int _ii_self_volts( lua_State* L ){ - int chan = luaL_checknumber(L, 1); - float val = luaL_checknumber(L, 2); - lua_settop(L, 0); - lua_getglobal(L, "output"); // 1 - lua_pushnumber(L, chan); // 2 - lua_gettable(L, -2); // output[chan] onto stack @2 - lua_pushnumber(L, val); // 3 - lua_setfield(L, 2, "volts"); - lua_settop(L, 0); - return 0; -} - -// function(chan,val) output[chan].volts = val end -static int _ii_self_slew( lua_State* L ){ - int chan = luaL_checknumber(L, 1); - float slew = luaL_checknumber(L, 2); - lua_settop(L, 0); - lua_getglobal(L, "output"); // 1 - lua_pushnumber(L, chan); // 2 - lua_gettable(L, -2); // output[chan] onto stack @2 - lua_pushnumber(L, slew); // 3 - lua_setfield(L, 2, "slew"); - lua_settop(L, 0); - return 0; -} - -// function() crow.reset() end -static int _ii_self_reset( lua_State* L ){ - lua_getglobal(L, "crow"); // 1 - lua_getfield(L, 1, "reset"); - lua_call(L, 0, 0); - lua_settop(L, 0); - return 0; -} - -// function(chan,ms,volts,pol) output[chan](pulse(ms,volts,pol)) end -static int _ii_self_pulse( lua_State* L ){ - int chan = luaL_checknumber(L, 1); - float ms = luaL_checknumber(L, 2); - float volts = luaL_checknumber(L, 3); - float pol = luaL_checknumber(L, 4); - lua_settop(L, 0); - - lua_getglobal(L, "output"); // 1 - lua_pushnumber(L, chan); // 2 - lua_gettable(L, -2); // output[chan] onto stack @2 - - lua_getglobal(L, "pulse"); // 3 - lua_pushnumber(L, ms); - lua_pushnumber(L, volts); - lua_pushnumber(L, pol); - lua_call(L, 3, 1); // calls 'ramp' and leaves asl table @3 - lua_call(L, 1, 0); // calls output[chan]({asl-table}) - lua_settop(L, 0); - return 0; -} - -// function(chan,atk,rel,volts) output[chan](ar(atk,rel,volts)) end -static int _ii_self_ar( lua_State* L ){ - int chan = luaL_checknumber(L, 1); - float atk = luaL_checknumber(L, 2); - float rel = luaL_checknumber(L, 3); - float volts = luaL_checknumber(L, 4); - lua_settop(L, 0); - - lua_getglobal(L, "output"); // 1 - lua_pushnumber(L, chan); // 2 - lua_gettable(L, -2); // output[chan] onto stack @2 - - lua_getglobal(L, "ar"); // 3 - lua_pushnumber(L, atk); - lua_pushnumber(L, rel); - lua_pushnumber(L, volts); - lua_call(L, 3, 1); // calls 'ar' and leaves asl table @3 - lua_call(L, 1, 0); // calls output[chan]({asl-table}) - lua_settop(L, 0); - return 0; -} - - -// -- convert freq to seconds where freq==0 is 1Hz -// function(chan,freq,level,skew) output[chan](ramp(math.pow(2,-freq),skew,level)) end -static int _ii_self_lfo( lua_State* L ){ - int chan = luaL_checknumber(L, 1); - float freq = luaL_checknumber(L, 2); - float level = luaL_checknumber(L, 3); - float skew = luaL_checknumber(L, 4); - lua_settop(L, 0); - - lua_getglobal(L, "output"); // 1 - lua_pushnumber(L, chan); // 2 - lua_gettable(L, -2); // output[chan] onto stack @2 - - lua_getglobal(L, "ramp"); // 3 - lua_pushnumber(L, powf(2.0, -freq)); - lua_pushnumber(L, skew); - lua_pushnumber(L, level); - lua_call(L, 3, 1); // calls 'ramp' and leaves asl table @3 - lua_call(L, 1, 0); // calls output[chan]({asl-table}) - lua_settop(L, 0); - return 0; -} - -static int _ii_follow_reset( lua_State* L ){ - lua_getglobal(L, "ii"); // @1 - lua_getfield(L, 1, "self"); // @2 - - lua_pushcfunction(L, _ii_self_volts); // @3 - lua_setfield(L, 2, "volts"); - lua_pushcfunction(L, _ii_self_slew); - lua_setfield(L, 2, "slew"); - lua_pushcfunction(L, _ii_self_reset); - lua_setfield(L, 2, "reset"); - lua_pushcfunction(L, _ii_self_pulse); - lua_setfield(L, 2, "pulse"); - lua_pushcfunction(L, _ii_self_ar); - lua_setfield(L, 2, "ar"); - lua_pushcfunction(L, _ii_self_lfo); - lua_setfield(L, 2, "lfo"); - - lua_settop(L, 0); - return 0; -} - - -// C.tell( 'output', channel, get_state( channel )) -static int _tell_get_out( lua_State* L ){ - int chan = luaL_checknumber(L, -1); - Caw_printf( "^^output(%i,%f)", chan, (double)AShaper_get_state(chan-1)); - lua_settop(L, 0); - return 0; -} - -// C.tell( 'stream', channel, io_get_input( channel )) -static int _tell_get_cv( lua_State* L ){ - int chan = luaL_checknumber(L, -1); - Caw_printf( "^^stream(%i,%f)", chan, (double)IO_GetADC(chan-1)); - lua_settop(L, 0); - return 0; -} diff --git a/lib/l_crowlib.h b/lib/l_crowlib.h deleted file mode 100644 index e40128bf..00000000 --- a/lib/l_crowlib.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "../submodules/lua/src/lua.h" // in header -#include "../submodules/lua/src/lauxlib.h" -#include "../submodules/lua/src/lualib.h" - -// initialize the default crow environment variables & data structures -void l_crowlib_init(lua_State* L); - -// destroys user init() function and replaces it with a void fn -void l_crowlib_emptyinit(lua_State* L); - -// execute crow.reset() which reverts state of all modules to default -int l_crowlib_crow_reset( lua_State* L ); - -int l_crowlib_justvolts(lua_State *L); -int l_crowlib_just12(lua_State *L); -int l_crowlib_hztovolts(lua_State *L); diff --git a/lib/l_ii_mod.c b/lib/l_ii_mod.c deleted file mode 100644 index 3f7e631d..00000000 --- a/lib/l_ii_mod.c +++ /dev/null @@ -1,288 +0,0 @@ -#include "l_ii_mod.h" - -#include -#include - -// #include "l_ii_mod_gen.h" // include code-generated data structs -#include "../build/ii_mod_gen.h" // GENERATED BY BUILD PROCESS -#include "caw.h" -#include "ii.h" - -//////////////////////////////////////////////// -// global vars -// set as commands are executed -static uint8_t active_address = 0x0; -static uint8_t active_cmd = 0x0; -static ii_box_t* active_box = NULL; - - -//////////////////////////////////////////////// -// search functions -// peer into the generated structures - -static ii_box_t* find_mod_struct_by_address(uint8_t addr){ - // TODO searching manually for now - // in future i can add a static table of addresses for direct lookup - for(int i=0; iaddresses; - for(int a=0; aname, name) == 0){ - return ii_mods[i]; - } - } - return NULL; -} - -static const char* find_cmd_name(ii_box_t* box, uint8_t cmd){ - // this fn is used to create userspace callbacks (ie from getters) - // search backward as getters are 2nd half of command list - const ii_mod_cmds_t* cmds = box->commands; - for(int i=box->command_count-1; i>=0; i--){ - if(cmds[i].cmd == cmd){ - return cmds[i].name; - } - } - return NULL; -} - -static int query_to_cmd(ii_box_t* box, const char* str){ - // search backward as getters are 2nd half of command list - const ii_mod_cmds_t* cmds = box->commands; - for(int i=box->command_count-1; i>=0; i--){ - if(strcmp(cmds[i].name, str) == 0){ - return cmds[i].cmd; - } - } - return 0xFF; -} - -static int string_to_cmd(ii_box_t* box, const char* str){ - const ii_mod_cmds_t* cmds = box->commands; - for(int i=0; icommand_count; i++){ - if(strcmp(cmds[i].name, str) == 0){ - return cmds[i].cmd; - } - } - return 0xFF; -} - -static ii_box_t* find_mod_struct_from_table(lua_State* L, int self_stack_index){ - lua_getfield(L, self_stack_index, "_name"); // push the device name onto TOS - size_t len = 0; - const char* name = lua_tolstring(L, -1, &len); - // len now contains the length of the string. use for fast lookup - return find_mod_struct_by_name(name, len); -} - -static int find_addr_ix(ii_box_t* box, int addr_now){ - // returns the 1-based index into .addresses that is currently in .addr - uint8_t* addrs = box->addresses; - for(int i=0; i= II_MAX_ADDRESSES) addr_ix = 0; // protect against out of bounds lookup - - ii_box_t* box = find_mod_struct_from_table(L, 1); - - // now set the current address in thebox - int new_addr = box->addresses[addr_ix]; - if(new_addr){ // protect against 0 (ie. invalid addresses) - box->addr = new_addr; - } - - lua_settop(L, 1); // returns self which still sits at index 1 - return 1; -} - -///////////////////////////////////////////////////// -// generic fns for executing __index metamethod of the provided module - -static int __index_help( lua_State* L ){ - // NOTE: active_address must already be set - printf("i2c help %i\n", active_address); - Caw_stream_constchar( ii_list_cmds(active_address) ); - lua_settop(L, 0); - return 0; -} - -static int __index_event( lua_State* L ){ - // this is the generic event printer - - double data = luaL_checknumber(L, 2); - lua_getfield(L, 1, "name"); - const char* name = luaL_checkstring(L, -1); - lua_getfield(L, 1, "device"); - int device = luaL_checkinteger(L, -1); - lua_getfield(L, 1, "arg"); - double arg = luaL_checknumber(L, -1); - - Caw_printf( "^^ii.%s({name=[[%s]],device=%i,arg=%g},%g)" - , active_box->name - , name - , device - , arg - , data); - - lua_settop(L, 0); - return 0; -} - -static int __index_get( lua_State* L ){ - // lua: ii_lead with check on validity of cmd - const char* cmd_str = luaL_checkstring(L, 1); - int query_cmd = query_to_cmd(active_box, cmd_str); - if(query_cmd == 0xFF) - return luaL_error(L, "getter not found for '%s'", cmd_str); - // this should select a cmd struct so we can arity check - float data[4] = {0,0,0,0}; // always zero out data -// TODO lookup number of args & arity check -// then only copy that number (warn of over/underflow) - int nargs = lua_gettop(L) - 1; // reduce for 'string' - if(nargs > 4) nargs = 4; // limit to 4 ii arguments - for(int i=0; ierror on too few -// ->warn on too many - if(nargs > 4) nargs = 4; // limit to 4 ii arguments - for(int i=0; iaddr; // default to the actual set address - - // grab the command-string name - size_t len = 0; - const char* name = lua_tolstring(L, 2, &len); - - lua_settop(L, 0); // clear stack - - // search for the known strings - if(strcmp(name, "help") == 0){ - // we use the first address for help lookup - active_address = active_box->addresses[0]; - lua_pushcfunction(L, __index_help); - } else if(strcmp(name, "event") == 0){ - lua_pushcfunction(L, __index_event); - } else if(strcmp(name, "get") == 0){ - lua_pushcfunction(L, __index_get); - } else { // and now search for a command - active_cmd = string_to_cmd(active_box, name); - if(active_cmd == 0xFF){ - return luaL_error(L, "can't find: ii.%s.%s", active_box->name, name); - } - lua_pushcfunction(L, __index_command); - } - return 1; -} - -static int l_ii_cmd_from_ix( lua_State* L ){ - uint8_t addr = luaL_checkinteger(L, 1); - uint8_t cmd = luaL_checkinteger(L, 2); - lua_settop(L,0); - ii_box_t* box = find_mod_struct_by_address(addr); - if(box == NULL) - return luaL_error(L, "couldn't find address"); - lua_pushstring(L, box->name); - const char* cmd_name = find_cmd_name(box, cmd); - if(cmd_name == NULL) - return luaL_error(L, "couldn't find cmd"); - lua_pushstring(L, cmd_name); - lua_pushinteger(L, find_addr_ix(box, addr)); - return 3; -} - -static int l_ii_load_mods( lua_State* L ){ - // load each module into the ii table - // ii. = ii.newmod('') - - // TODO rather than push string, we can push the address of the table - // this optimizes away a string search in find_mod_struct_by_name() - - // @1 (TOS) is `ii` global table - for(int i=0; iname; - lua_getfield(L, 1, "newmod"); // pushes ii.newmod function onto TOS @2 - lua_pushstring(L, name); // @3 - lua_call(L, 1, 1); // @2 - lua_setfield(L, 1, name); // -> leaves only 'ii' at TOS @1 - // loop is stack neutral - } - lua_settop(L, 0); - return 0; -} - -// array of all the available functions -static const struct luaL_Reg lib_ii_mod[]= - { { "c_ii_setaddress" , l_ii_setaddress } - , { "c_ii_index" , l_ii_index } - , { "c_ii_cmd" , l_ii_cmd_from_ix } - , { "c_ii_load" , l_ii_load_mods } - , { NULL , NULL } - }; - -static void linkctolua( lua_State *L ) -{ - // Make C fns available to Lua - uint8_t fn = 0; - while( lib_ii_mod[fn].func != NULL ){ - lua_register( L, lib_ii_mod[fn].name, lib_ii_mod[fn].func ); - fn++; - } -} - -void l_ii_mod_preload(lua_State* L){ - // load C funcs into lua env - linkctolua(L); -} - diff --git a/lib/l_ii_mod.h b/lib/l_ii_mod.h deleted file mode 100644 index c36c6a55..00000000 --- a/lib/l_ii_mod.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "../submodules/lua/src/lua.h" // lua_State* -#include "../submodules/lua/src/lauxlib.h" -#include "../submodules/lua/src/lualib.h" - -typedef struct{ - uint8_t cmd; - const char* name; -} ii_mod_cmds_t; - -#define II_MAX_ADDRESSES 8 - -typedef struct{ - uint8_t addr; - const char* name; - uint8_t addresses[II_MAX_ADDRESSES]; // leave room for up to 8 so we have a static size - const ii_mod_cmds_t* commands; - int command_count; -} ii_box_t; - -void l_ii_mod_preload(lua_State* L); diff --git a/lib/lualink.c b/lib/lualink.c deleted file mode 100644 index cc6d1578..00000000 --- a/lib/lualink.c +++ /dev/null @@ -1,1259 +0,0 @@ -#include "lib/lualink.h" - -#include -#include // strcmp(), strlen() -#include - -// Lua itself -//#include "../submodules/lua/src/lua.h" // in header -#include "../submodules/lua/src/lauxlib.h" -#include "../submodules/lua/src/lualib.h" - -// Hardware IO -#include "lib/slopes.h" // S_toward -#include "lib/casl.h" // C-ASL -#include "lib/ashapes.h" // AShaper_unset_scale(), AShaper_set_scale() -#include "lib/detect.h" // Detect* -#include "lib/caw.h" // Caw_send_*() -#include "lib/ii.h" // ii_*() -#include "lib/bootloader.h" // bootloader_enter() -#include "lib/metro.h" // metro_start() metro_stop() metro_set_time() -#include "lib/clock.h" // clock_*() -#include "lib/io.h" // IO_GetADC() -#include "../ll/adda.h" // CAL_*() -#include "../ll/cal_ll.h" // CAL_LL_ActiveChannel() -#include "../ll/system.h" // getUID_Word() -#include "../ll/i2c.h" // I2C_SetTimings(u8) -#include "lib/events.h" // event_t event_post() -#include "stm32f7xx_hal.h" // HAL_GetTick() -#include "stm32f7xx_it.h" // CPU_GetCount() - -// Lua lib C implementations -// as much low-level functionality is in here as possible -// thus keeping the lua VM as free as possible -#include "l_bootstrap.h" -#include "l_crowlib.h" - - -#define WATCHDOG_FREQ 0x100000 // ~1s how often we run the watchdog -#define WATCHDOG_COUNT 2 // how many watchdogs before 'frozen' - - -// Basic crow script -#include "build/First.h" - -// Private prototypes -static void Lua_linkctolua( lua_State* L ); -static float Lua_check_memory( void ); -static int Lua_call_usercode( lua_State* L, int nargs, int nresults ); -static int Lua_handle_error( lua_State* L ); -static void timeouthook( lua_State* L, lua_Debug* ar ); - -// Handler prototypes -void L_handle_asl_done( event_t* e ); -void L_handle_metro( event_t* e ); -void L_handle_stream( event_t* e ); -void L_handle_change( event_t* e ); -void L_handle_ii_leadRx( event_t* e );; -void L_handle_ii_followRx( event_t* e ); -void L_handle_ii_followRx_cont( uint8_t cmd, int args, float* data ); -void L_handle_window( event_t* e ); -void L_handle_in_scale( event_t* e ); -void L_handle_volume( event_t* e ); -void L_handle_peak( event_t* e ); -void L_handle_clock_resume( event_t* e ); -void L_handle_clock_start( event_t* e ); -void L_handle_clock_stop( event_t* e ); -void L_handle_freq( event_t* e ); - -void _printf(char* error_message) -{ - printf("%s\n",error_message); -} - -lua_State* L; // global access for 'reset-environment' - -// Public functions -lua_State* Lua_Init(void) -{ - L = luaL_newstate(); - luaL_openlibs(L); - Lua_linkctolua(L); - l_bootstrap_init(L); // redefine dofile(), print(), load crowlib - return L; -} - -lua_State* Lua_ReInit_Environment(lua_State* L){ - // clear user-created globals - luaL_dostring(L, "for k,_ in pairs(_user) do\n" - "_G[k] = nil\n" - "end\n" - "_G._user = {}\n"); - // init() has to be manually reset to the void function - l_crowlib_emptyinit(L); - // cleanup memory to get back to a blank slate - lua_gc(L, LUA_GCCOLLECT, 1); - lua_gc(L, LUA_GCCOLLECT, 1); - return L; -} - -lua_State* Lua_Reset( void ) -{ - printf("Lua_Reset\n"); - - // cleanup any C-based event generators - Metro_stop_all(); - for( int i=0; i<2; i++ ){ - Detect_none( Detect_ix_to_p(i) ); - } - for( int i=0; i<4; i++ ){ - S_toward( i, 0.0, 0.0, SHAPE_Linear, NULL ); - } - events_clear(); - clock_cancel_coro_all(); - - // set all crowlib modules to default states / callbacks - l_crowlib_crow_reset(L); - - // delete all user globals, but keep overall Lua env - // we do this to avoid memory fragmentation when resetting env - return Lua_ReInit_Environment(L); -} - -void Lua_load_default_script( void ) -{ - Lua_eval(L, (const char*)build_First_lc - , build_First_lc_len - , "=First.lua" - ); -} - -void Lua_DeInit(void) -{ - lua_close(L); -} - -// C-fns accessible to lua - -// NB these static functions are prefixed with '_' -// to avoid shadowing similar-named extern functions in other modules -// and also to distinguish from extern 'L_' functions. - -static int _debug( lua_State *L ) -{ - const char* msg = luaL_checkstring(L, 1); - lua_pop( L, 1 ); - printf( "%s\n",(char*)msg); - lua_settop(L, 0); - return 0; -} -static int _print_serial( lua_State *L ) -{ - Caw_send_luachunk( (char*)luaL_checkstring(L, 1) ); - lua_pop( L, 1 ); - lua_settop(L, 0); - return 0; -} -static int _print_tell( lua_State *L ) -{ - int nargs = lua_gettop(L); - // nb: luaL_checkstring() will coerce ints & nums into strings - switch( nargs ){ - case 0: - return luaL_error(L, "no event to tell."); - case 1: - Caw_printf( "^^%s()", luaL_checkstring(L, 1) ); - break; - case 2: - Caw_printf( "^^%s(%s)", luaL_checkstring(L, 1) - , luaL_checkstring(L, 2) ); - break; - case 3: - Caw_printf( "^^%s(%s,%s)", luaL_checkstring(L, 1) - , luaL_checkstring(L, 2) - , luaL_checkstring(L, 3) ); - break; - case 4: - Caw_printf( "^^%s(%s,%s,%s)", luaL_checkstring(L, 1) - , luaL_checkstring(L, 2) - , luaL_checkstring(L, 3) - , luaL_checkstring(L, 4) ); - break; - case 5: - Caw_printf( "^^%s(%s,%s,%s,%s)", luaL_checkstring(L, 1) - , luaL_checkstring(L, 2) - , luaL_checkstring(L, 3) - , luaL_checkstring(L, 4) - , luaL_checkstring(L, 5) ); - break; - default: - return luaL_error(L, "too many args to tell."); - } - lua_pop( L, nargs ); - lua_settop(L, 0); - return 0; -} -static int _bootloader( lua_State *L ) -{ - bootloader_enter(); - return 0; -} -static int _unique_id( lua_State *L ) -{ - lua_pushinteger(L, getUID_Word(0)); - lua_pushinteger(L, getUID_Word(4)); - lua_pushinteger(L, getUID_Word(8)); - return 3; -} -static int _time( lua_State *L ) -{ - lua_pushinteger(L, HAL_GetTick()); - return 1; -} -static int _cpu_time( lua_State *L ) -{ - // returns count of background loops for the last 8ms - lua_pushinteger(L, CPU_GetCount()); - return 1; -} -static int _get_state( lua_State *L ) -{ - float s = AShaper_get_state( luaL_checkinteger(L, 1)-1 ); - lua_pop( L, 1 ); - lua_pushnumber( L, s ); - return 1; -} -static int _set_scale( lua_State *L ) -{ - // statically save the mod & scaling options - // if omitting mod & scaling, they use the most recent value of mod/scaling - // if no value ever provided, the initial values act as defaults - // NB: shared between outputs. if you need separate mod/scale, must be explicit - static float mod = 12.0; // default to 12TET - static float scaling = 1.0; // default to v/8 - - int nargs = lua_gettop(L); - // first arg is index! - - // special cases: - if( nargs == 1 ){ // no user arguments - float divs[1] = {0.0}; - AShaper_set_scale( luaL_checknumber( L, 1 )-1 // index is 1-based in lua - , divs - , 1 - , 1 - , 1.0/12.0 // hack it not to need the array - ); - lua_pop( L, 1 ); // pop index - return 0; - } else if( lua_isstring( L, 2 ) ){ // if arg1 == 'none' -> disable scaling - AShaper_unset_scale( luaL_checknumber( L, 1 )-1 ); // lua is 1-based - lua_pop( L, 2 ); - return 0; - } - - // arg1 is a list: - // empty list == chromatic - // 12TET semitones based at 0 - // just ratios relative to 1/1 in the [1,2) range - int tlen = lua_rawlen( L, 2 ); // length of the table - float divs[tlen]; - for( int i=0; i= 3 ){ - // TODO allow string = 'just' to select JI mode for note list - mod = luaL_checknumber( L, 3 ); - } - - if( nargs >= 4 ){ - scaling = luaL_checknumber( L, 4 ); - } - - AShaper_set_scale( luaL_checknumber( L, 1 )-1 // index is 1-based in lua - , divs - , tlen - , mod - , scaling - ); - - lua_pop( L, nargs ); - return 0; -} -static int _io_get_input( lua_State *L ) -{ - float adc = IO_GetADC( luaL_checkinteger(L, 1)-1 ); - lua_pop( L, 1 ); - lua_pushnumber( L, adc ); - return 1; -} -static int _set_input_none( lua_State *L ) -{ - uint8_t ix = luaL_checkinteger(L, 1)-1; - Detect_t* d = Detect_ix_to_p( ix ); // Lua is 1-based - if(d){ // valid index - Detect_none( d ); - } - lua_pop( L, 1 ); - lua_settop(L, 0); - return 0; -} -static int _set_input_stream( lua_State *L ) -{ - uint8_t ix = luaL_checkinteger(L, 1)-1; - Detect_t* d = Detect_ix_to_p( ix ); // Lua is 1-based - if(d){ // valid index - Detect_stream( d - , L_queue_stream - , luaL_checknumber(L, 2) - ); - } - lua_pop( L, 2 ); - lua_settop(L, 0); - return 0; -} -static int _set_input_change( lua_State *L ) -{ - uint8_t ix = luaL_checkinteger(L, 1)-1; - Detect_t* d = Detect_ix_to_p( ix ); // Lua is 1-based - if(d){ // valid index - Detect_change( d - , L_queue_change - , luaL_checknumber(L, 2) - , luaL_checknumber(L, 3) - , Detect_str_to_dir( luaL_checkstring(L, 4) ) - ); - } - lua_pop( L, 4 ); - lua_settop(L, 0); - return 0; -} -static int _set_input_window( lua_State *L ) -{ - uint8_t ix = luaL_checkinteger(L, 1)-1; - Detect_t* d = Detect_ix_to_p( ix ); // Lua is 1-based - if(d){ // valid index - // capture window table from lua - int wLen = lua_rawlen( L, 2 ); // length of the table - float wins[wLen]; - for( int i=0; i 2 - && nargs <= 6 ){ - for( int i=0; i<(nargs-2); i++ ){ - data[i] = luaL_checknumber(L, i+3); - } - } - if( ii_leader_enqueue( luaL_checkinteger(L, 1) // address - , luaL_checkinteger(L, 2) // command - , data - ) ){ printf("ii_lead failed\n"); } - lua_settop(L, 0); - return 0; -} -static int _ii_lead_bytes( lua_State *L ) -{ - int nargs = lua_gettop(L); - uint8_t rx_len = 0; // if no length provided, assume 0 - if(nargs < 2 || nargs > 3){ return 0; } - if(nargs == 3){ // explict length provided - rx_len = (uint8_t)luaL_checkinteger(L, 3); - } - uint8_t address = luaL_checkinteger(L, 1); - size_t len; - uint8_t *data = (uint8_t *)luaL_checklstring(L, 2, &len); - if( ii_leader_enqueue_bytes( address - , data - , (uint8_t)len - , rx_len - ) ){ printf("ii_lead_bytes failed\n"); } - lua_settop(L, 0); - return 0; -} - -static int _ii_address( lua_State *L ) -{ - ii_set_address( luaL_checkinteger(L, 1) ); - lua_pop( L, 1 ); - lua_settop(L, 0); - return 0; -} -static int _ii_get_address( lua_State *L ) -{ - lua_pushinteger( L, ii_get_address() ); - return 1; -} -static int _metro_start( lua_State* L ) -{ - static int ix = 0; - float seconds = -1.0; // metro will re-use previous value - int count = -1; // default: infinite - int stage = 0; - - int nargs = lua_gettop(L); - if( nargs > 0 ){ ix = (int) luaL_checkinteger(L, 1) - 1; } // 1-ix'd - if( nargs > 1 ){ seconds = (float)luaL_checknumber(L, 2); } - if( nargs > 2 ){ count = (int)luaL_checkinteger(L, 3); } - if( nargs > 3 ){ stage = (int)luaL_checkinteger(L, 4) - 1; } // 1-ix'd - lua_pop( L, 4 ); - - if( seconds >= 0.0 ){ // if negative, leave previous time - // limit to 500uS to avoid crash - Metro_set_time( ix, (seconds < 0.0005) ? 0.0005 : seconds ); - } - Metro_set_count( ix, count ); - Metro_set_stage( ix, stage ); - Metro_start( ix ); - lua_settop(L, 0); - return 0; -} -static int _metro_stop( lua_State* L ) -{ - if( lua_gettop(L) != 1 ){ return luaL_error(L, "wrong number of arguments"); } - - int ix = (int)luaL_checkinteger(L, 1) - 1; // 1-ix'd - lua_pop( L, 1 ); - Metro_stop(ix); - lua_settop(L, 0); - return 0; -} -static int _metro_set_time( lua_State* L ) -{ - if( lua_gettop(L) != 2 ){ return luaL_error(L, "wrong number of arguments"); } - - int ix = (int)luaL_checkinteger(L, 1) - 1; // 1-ix'd - float seconds = (float)luaL_checknumber(L, 2); - lua_pop( L, 2 ); - - if( seconds >= 0.0 ){ // if negative, leave previous time - // limit to 500uS to avoid crash - Metro_set_time( ix, (seconds < 0.0005) ? 0.0005 : seconds ); - } - - lua_settop(L, 0); - return 0; -} - -static int _calibrate_source( lua_State* L ) -{ - int chan = -1; - const char* src = luaL_checkstring(L, 1); // get string, or coerce int to string - if( strlen(src) > 1 ){ // assume string - switch(src[0]){ case 'g':{ chan=5; break; } - case '2':{ chan=4; break; } - } - } else { - switch(src[0]){ case '1':{ chan=3; break; } - case '2':{ chan=2; break; } - case '3':{ chan=1; break; } - case '4':{ chan=0; break; } - } - } - if(chan != -1){ - CAL_LL_ActiveChannel(chan); - } else { - Caw_send_luachunk("cal.source: unknown source. use {1,2,3,4,'gnd','2v5'}"); - } - lua_pop(L, 1); - return 0; -} -static int _calibrate_get( lua_State* L ) -{ - int chan = luaL_checkinteger(L, 1); - const char* msg = luaL_checkstring(L, 2); - float r = CAL_Get(chan, (msg[0]=='o') ? CAL_Offset : CAL_Scale); - lua_pop(L, 2); - lua_pushnumber(L, r); - return 1; -} -static int _calibrate_set( lua_State* L ) -{ - int chan = luaL_checkinteger(L, 1); - const char* msg = luaL_checkstring(L, 2); - float val = luaL_checknumber(L, 3); - CAL_Set(chan, (msg[0]=='o') ? CAL_Offset : CAL_Scale, val); - lua_pop(L, 3); - return 0; -} -static int _calibrate_save( lua_State* L ) -{ - CAL_WriteFlash(); - return 0; -} - -// clock -static int _clock_cancel( lua_State* L ) -{ - int coro_id = (int)luaL_checkinteger(L, 1); - clock_cancel_coro(coro_id); - lua_pop(L, 1); - return 0; -} -static int _clock_schedule_sleep( lua_State* L ) -{ - int coro_id = (int)luaL_checkinteger(L, 1); - float seconds = luaL_checknumber(L, 2); - - if( seconds <= 0 ){ - L_queue_clock_resume(coro_id); // immediate callback - } else { - clock_schedule_resume_sleep(coro_id, seconds); - } - lua_pop(L, 2); - return 0; -} -static int _clock_schedule_sync( lua_State* L ) -{ - int coro_id = (int)luaL_checkinteger(L, 1); - float beats = luaL_checknumber(L, 2); - - if (beats <= 0) { - L_queue_clock_resume(coro_id); // immediate callback - } else { - clock_schedule_resume_sync(coro_id, beats); - } - lua_pop(L, 2); - return 0; -} -static int _clock_schedule_beatsync( lua_State* L ) -{ - int coro_id = (int)luaL_checkinteger(L, 1); - float beats = luaL_checknumber(L, 2); // FIXME i think the issue is FP rounding at high numbers - - if (beats <= 0) { - L_queue_clock_resume(coro_id); // immediate callback - } else { - clock_schedule_resume_beatsync(coro_id, beats); - } - lua_pop(L, 2); - return 0; -} -static int _clock_get_time_beats( lua_State* L ) -{ - lua_pushnumber(L, clock_get_time_beats()); - return 1; -} -static int _clock_get_tempo( lua_State* L ) -{ - lua_pushnumber(L, clock_get_tempo()); - return 1; -} -static int _clock_set_source( lua_State* L ) -{ - clock_set_source( (int)luaL_checkinteger(L, 1)-1 ); // lua is 1-based - lua_pop(L, 1); - return 0; -} -static int _clock_internal_set_tempo( lua_State* L ) -{ - float bpm = luaL_checknumber(L, 1); - clock_internal_set_tempo(bpm); - lua_pop(L, 1); - return 0; -} -static int _clock_internal_start( lua_State* L ) -{ - float new_beat = luaL_checknumber(L, 1); - clock_set_source(CLOCK_SOURCE_INTERNAL); - clock_internal_start(new_beat, true); - lua_pop(L, 1); - return 0; -} -static int _clock_internal_stop( lua_State* L ) -{ - clock_set_source(CLOCK_SOURCE_INTERNAL); - clock_internal_stop(); - return 0; -} - -static int _pub_view_in( lua_State* L ) -{ - int chan = luaL_checkinteger(L, 1)-1; // lua is 1-based - bool state; - if(lua_isboolean(L, 2)){ state = lua_toboolean(L, 2); } - else{ state = (bool)lua_tointeger(L, 2); } - IO_public_set_view(chan+4, state); - lua_pop(L, 2); - return 0; -} -static int _pub_view_out( lua_State* L ) -{ - int chan = luaL_checkinteger(L, 1)-1; // lua is 1-based - bool state; - if(lua_isboolean(L, 2)){ state = lua_toboolean(L, 2); } - else{ state = (bool)lua_tointeger(L, 2); } - IO_public_set_view(chan, state); - lua_pop(L, 2); - return 0; -} - -// i2c debug control -static int _i2c_set_timings( lua_State *L ) -{ - uint32_t state = 0; - switch(lua_type(L, 1)){ - case LUA_TSTRING: state = 2; break; // CLASSIC MODE - case LUA_TBOOLEAN: state = lua_toboolean(L, 1); break; - default: state = lua_tointeger(L, 1); break; - } - I2C_SetTimings(state); - lua_pop(L, 1); - return 0; -} - - -// array of all the available functions -static const struct luaL_Reg libCrow[]= - // bootstrap - { { "c_dofile" , l_bootstrap_dofile } - , { "debug_usart" , _debug } - , { "print_serial" , _print_serial } - , { "tell" , _print_tell } - // system - , { "justvolts" , l_crowlib_justvolts } - , { "just12" , l_crowlib_just12 } - , { "hztovolts" , l_crowlib_hztovolts } - // crowlib - , { "sys_bootloader" , _bootloader } - , { "unique_id" , _unique_id } - , { "time" , _time } - , { "cputime" , _cpu_time } - , { "i2c_fastmode" , _i2c_set_timings } - //, { "sys_cpu_load" , _sys_cpu } - // io - , { "get_state" , _get_state } - , { "set_output_scale" , _set_scale } - , { "io_get_input" , _io_get_input } - , { "set_input_none" , _set_input_none } - , { "set_input_stream" , _set_input_stream } - , { "set_input_change" , _set_input_change } - , { "set_input_scale" , _set_input_scale } - , { "set_input_window" , _set_input_window } - , { "set_input_volume" , _set_input_volume } - , { "set_input_peak" , _set_input_peak } - , { "set_input_freq" , _set_input_freq } - , { "set_input_clock" , _set_input_clock } - // casl - , { "casl_describe" , _casl_describe } - , { "casl_action" , _casl_action } - , { "casl_defdynamic" , _casl_defdynamic } - , { "casl_cleardynamics", _casl_cleardynamics } - , { "casl_setdynamic" , _casl_setdynamic } - , { "casl_getdynamic" , _casl_getdynamic } - // usb - , { "send_usb" , _send_usb } - // i2c - , { "ii_list_modules" , _ii_list_modules } - , { "ii_list_commands" , _ii_list_commands } - , { "ii_pullup" , _ii_pullup } - , { "ii_lead" , _ii_lead } - , { "ii_lead_bytes" , _ii_lead_bytes } - , { "ii_set_add" , _ii_address } - , { "ii_get_add" , _ii_get_address } - // metro - , { "metro_start" , _metro_start } - , { "metro_stop" , _metro_stop } - , { "metro_set_time" , _metro_set_time } - // calibration - , { "calibrate_source" , _calibrate_source } - , { "calibrate_get" , _calibrate_get } - , { "calibrate_set" , _calibrate_set } - , { "calibrate_save" , _calibrate_save } - // clock - , { "clock_cancel" , _clock_cancel } - , { "clock_schedule_sleep" , _clock_schedule_sleep } - , { "clock_schedule_sync" , _clock_schedule_sync } - , { "clock_schedule_beat" , _clock_schedule_beatsync } - , { "clock_get_time_beats" , _clock_get_time_beats } - , { "clock_get_tempo" , _clock_get_tempo } - , { "clock_set_source" , _clock_set_source } - // clock.internal - , { "clock_internal_set_tempo" , _clock_internal_set_tempo } - , { "clock_internal_start" , _clock_internal_start } - , { "clock_internal_stop" , _clock_internal_stop } - // public - , { "pub_view_in" , _pub_view_in } - , { "pub_view_out" , _pub_view_out } - - , { NULL , NULL } - }; -// make functions available to lua -static void Lua_linkctolua( lua_State *L ) -{ - // Make C fns available to Lua - uint8_t fn = 0; - while( libCrow[fn].func != NULL ){ - lua_register( L, libCrow[fn].name, libCrow[fn].func ); - fn++; - } -} - -uint8_t Lua_eval( lua_State* L - , const char* script - , size_t script_len - , const char* chunkname - ){ - int error = luaL_loadbuffer( L, script, script_len, chunkname ); - if( error != LUA_OK ){ - Caw_send_luachunk( (char*)lua_tostring( L, -1 ) ); - lua_pop( L, 1 ); - return 1; - } - - if( (error |= Lua_call_usercode( L, 0, 0 )) != LUA_OK ){ - lua_pop( L, 1 ); - switch( error ){ - case LUA_ERRSYNTAX: Caw_send_luachunk("syntax error."); break; - case LUA_ERRMEM: Caw_send_luachunk("not enough memory."); break; - case LUA_ERRRUN: Caw_send_luachunk("runtime error."); break; - case LUA_ERRERR: Caw_send_luachunk("error in error handler."); break; - default: break; - } - return 1; - } - return 0; -} - -static float Lua_check_memory( void ) -{ - lua_getglobal(L,"collectgarbage"); - lua_pushstring(L, "count"); - lua_pcall(L,1,1,0); // NOT PROTECTED (called from watchdog) - float mem = luaL_checknumber(L, 1); - lua_pop(L,1); - return mem; -} - -void Lua_crowbegin( void ) -{ - printf("init()\n"); // call in C to avoid user seeing in lua - lua_getglobal(L,"init"); - if( Lua_call_usercode(L,0,0) != LUA_OK ){ - lua_pop(L, 1); - } - Caw_send_luachunk("^^ready()"); // inform host that script is initialized -} - - -// Watchdog timer for infinite looped Lua scripts -volatile int watchdog = WATCHDOG_COUNT; -static void timeouthook( lua_State* L, lua_Debug* ar ) -{ - if( --watchdog <= 0 ){ - Caw_send_luachunk("CPU timed out."); - lua_sethook(L, timeouthook, LUA_MASKLINE, 0); // error until top - luaL_error(L, "user code timeout exceeded"); - } -} - -static int Lua_handle_error( lua_State *L ) -{ - const char *msg = lua_tostring( L, 1 ); - if( msg == NULL ){ - if( luaL_callmeta( L, 1, "__tostring" ) - && lua_type ( L, -1 ) == LUA_TSTRING ) { - return 1; - } else { - msg = lua_pushfstring( L - , "(error object is a %s value)" - , luaL_typename( L, 1 ) ); - } - } - luaL_traceback( L, L, msg, 1 ); - char* traceback = (char*)lua_tostring( L, -1 ); - Caw_send_luachunk( traceback ); - _printf( traceback ); - return 1; -} - -static int Lua_call_usercode( lua_State* L, int nargs, int nresults ) -{ - lua_sethook(L, timeouthook, LUA_MASKCOUNT, WATCHDOG_FREQ); // reset timeout hook - watchdog = WATCHDOG_COUNT; // reset timeout hook counter - - int errFunc = lua_gettop(L) - nargs; - lua_pushcfunction( L, Lua_handle_error ); - lua_insert( L, errFunc ); - int status = lua_pcall(L, nargs, nresults, errFunc); - lua_remove( L, errFunc ); - - lua_sethook(L, timeouthook, 0, 0); - - return status; -} - - -// Public Callbacks from C to Lua -void L_queue_asl_done( int id ) -{ - event_t e = { .handler = L_handle_asl_done - , .index.i = id - }; - event_post(&e); -} - -// forward directly to output[e->index.i].done() -void L_handle_asl_done( event_t* e ) -{ - lua_getglobal(L, "output"); // @1 - lua_pushinteger(L, e->index.i + 1); // 1-ix'd - lua_gettable(L, 1); // @2 - lua_getfield(L, 2, "done"); - Lua_call_usercode(L, 0, 0); // lua_call with timeout hook - lua_settop(L, 0); -} - -void L_queue_metro( int id, int state ) -{ - event_t e = { .handler = L_handle_metro - , .index.i = id - , .data.i = state - }; - event_post(&e); -} -void L_handle_metro( event_t* e ) -{ - lua_getglobal(L, "metro_handler"); - lua_pushinteger(L, e->index.i +1); // 1-ix'd - lua_pushinteger(L, e->data.i +1); // 1-ix'd - if( Lua_call_usercode(L, 2, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_stream( int id, float state ) -{ - event_t e = { .handler = L_handle_stream - , .index.i = id - , .data.f = state - }; - event_post(&e); -} -void L_handle_stream( event_t* e ) -{ - lua_getglobal(L, "stream_handler"); - lua_pushinteger(L, e->index.i +1); // 1-ix'd - lua_pushnumber(L, e->data.f); - if( Lua_call_usercode(L, 2, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_change( int id, float state ) -{ - event_t e = { .handler = L_handle_change - , .index.i = id - , .data.f = state - }; - event_post(&e); -} -void L_handle_change( event_t* e ) -{ - lua_getglobal(L, "change_handler"); - lua_pushinteger(L, e->index.i +1); // 1-ix'd - lua_pushnumber(L, e->data.f); - if( Lua_call_usercode(L, 2, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_ii_leadRx( uint8_t address, uint8_t cmd, float data, uint8_t arg ) -{ - event_t e = { .handler = L_handle_ii_leadRx - , .data.f = data - }; - e.index.u8s[0] = address; - e.index.u8s[1] = cmd; - e.index.u8s[2] = arg; - event_post(&e); -} -void L_handle_ii_leadRx( event_t* e ) -{ - lua_getglobal(L, "ii_LeadRx_handler"); - lua_pushinteger(L, e->index.u8s[0]); // address - lua_pushinteger(L, e->index.u8s[1]); // command - lua_pushinteger(L, e->index.u8s[2]); // arg - lua_pushnumber(L, e->data.f); - if( Lua_call_usercode(L, 4, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_ii_followRx( void ) -{ - event_t e = { .handler = L_handle_ii_followRx }; - event_post(&e); -} -void L_handle_ii_followRx( event_t* e ) -{ - // FIXME: should pass the 'cont' as a fnptr continuation - ii_process_dequeue_decode(); -} -void L_handle_ii_followRx_cont( uint8_t cmd, int args, float* data ) -{ - lua_getglobal(L, "ii_followRx_handler"); - lua_pushinteger(L, cmd); - int a = args; - while(a-- > 0){ - lua_pushnumber(L, *data++); - } - if( Lua_call_usercode(L, 1+args, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -// FIXME called directly from ii lib for now -float L_handle_ii_followRxTx( uint8_t cmd, int args, float* data ) -{ - lua_getglobal(L, "ii_followRxTx_handler"); - lua_pushinteger(L, cmd); - int a = args; - while(a-- > 0){ - lua_pushnumber(L, *data++); - } - if( Lua_call_usercode(L, 1+args, 1) != LUA_OK ){ - lua_pop( L, 1 ); - } - float n = luaL_checknumber(L, 1); - lua_pop( L, 1 ); - return n; -} - -void L_queue_in_scale( int id, float note ) -{ - event_t e = { .handler = L_handle_in_scale - , .index.i = id - }; - event_post(&e); -} -void L_handle_in_scale( event_t* e ) -{ - lua_getglobal(L, "scale_handler"); - Detect_t* d = Detect_ix_to_p( e->index.i ); - // TODO these should be wrapped in a table here rather than lua - lua_pushinteger(L, e->index.i +1); // 1-ix'd - lua_pushinteger(L, d->scale.lastIndex +1); // 1-ix'd - lua_pushinteger(L, d->scale.lastOct); - lua_pushnumber(L, d->scale.lastNote); - lua_pushnumber(L, d->scale.lastVolts); - if( Lua_call_usercode(L, 5, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_window( int id, float window ) -{ - event_t e = { .handler = L_handle_window - , .index.i = id - }; - if( window >= 0.0 ){ - e.data.u8s[0] = window; - e.data.u8s[1] = 1; - } else { - e.data.u8s[0] = -window; // flip sign for positive index - e.data.u8s[1] = 0; - } - event_post(&e); -} -void L_handle_window( event_t* e ) -{ - lua_getglobal(L, "window_handler"); - lua_pushinteger(L, e->index.i+1); // 1-ix'd - lua_pushinteger(L, e->data.u8s[0]); - lua_pushnumber(L, e->data.u8s[1]); - if( Lua_call_usercode(L, 3, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_volume( int id, float level ) -{ - event_t e = { .handler = L_handle_volume - , .index.i = id - , .data.f = level - }; - event_post(&e); -} -void L_handle_volume( event_t* e ) -{ - lua_getglobal(L, "volume_handler"); - lua_pushinteger(L, e->index.i+1); // 1-ix'd - lua_pushnumber(L, e->data.f); - if( Lua_call_usercode(L, 2, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_peak( int id, float ignore ) -{ - event_t e = { .handler = L_handle_peak - , .index.i = id - }; - event_post(&e); -} -void L_handle_peak( event_t* e ) -{ - lua_getglobal(L, "peak_handler"); - lua_pushinteger(L, e->index.i +1); // 1-ix'd - if( Lua_call_usercode(L, 1, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_freq( int id, float freq ) -{ - event_t e = { .handler = L_handle_freq - , .index.i = id - , .data.f = freq - }; - event_post(&e); -} -void L_handle_freq( event_t* e ) -{ - lua_getglobal(L, "freq_handler"); - lua_pushinteger(L, e->index.i +1); // 1-ix'd - lua_pushnumber(L, e->data.f); - if( Lua_call_usercode(L, 2, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_clock_resume( int coro_id ) -{ - event_t e = { .handler = L_handle_clock_resume - , .index.i = coro_id - }; - event_post(&e); -} -void L_handle_clock_resume( event_t* e ) -{ - lua_getglobal(L, "clock_resume_handler"); - lua_pushinteger(L, e->index.i); - if( Lua_call_usercode(L, 1, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_clock_start( void ) -{ - event_t e = { .handler = L_handle_clock_start }; - event_post(&e); -} -void L_handle_clock_start( event_t* e ) -{ - lua_getglobal(L, "clock_start_handler"); - if( Lua_call_usercode(L, 0, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} - -void L_queue_clock_stop( void ) -{ - event_t e = { .handler = L_handle_clock_stop }; - event_post(&e); -} -void L_handle_clock_stop( event_t* e ) -{ - lua_getglobal(L, "clock_stop_handler"); - if( Lua_call_usercode(L, 0, 0) != LUA_OK ){ - lua_pop( L, 1 ); - } -} diff --git a/lib/lualink.h b/lib/lualink.h deleted file mode 100644 index 2eca95c5..00000000 --- a/lib/lualink.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -// Lua itself -#include "../submodules/lua/src/lua.h" // lua_State* - -typedef void (*ErrorHandler_t)(char* error_message); - -extern volatile int CPU_count; // count from main.c - -lua_State* Lua_Init(void); -lua_State* Lua_Reset( void ); -void Lua_DeInit(void); - -void Lua_crowbegin( void ); -uint8_t Lua_eval( lua_State* L - , const char* script - , size_t script_len - , const char* chunkname - ); -void Lua_load_default_script( void ); - -// Event enqueue wrappers -extern void L_queue_asl_done( int id ); -extern void L_queue_metro( int id, int state ); -extern void L_queue_stream( int id, float state ); -extern void L_queue_change( int id, float state ); -extern void L_queue_window( int id, float window ); -extern void L_queue_volume( int id, float level ); -extern void L_queue_peak( int id, float ignore ); -extern void L_queue_freq( int id, float freq ); -extern void L_queue_in_scale( int id, float note ); -extern void L_queue_ii_leadRx( uint8_t address, uint8_t cmd, float data, uint8_t arg ); -extern void L_queue_ii_followRx( void ); -extern void L_queue_clock_resume( int coro_id ); -extern void L_queue_clock_start( void ); -extern void L_queue_clock_stop( void ); - -// Callback declarations -extern float L_handle_ii_followRxTx( uint8_t cmd, int args, float* data ); -extern void L_handle_ii_followRx_cont( uint8_t cmd, int args, float* data ); diff --git a/lib/metro.c b/lib/metro.c index a80b98f0..a06a0bab 100644 --- a/lib/metro.c +++ b/lib/metro.c @@ -5,7 +5,7 @@ #include #include "../ll/timers.h" // _Init() _Start() _Stop() _Set_Params() -#include "lualink.h" // L_handle_metro() +// #include "lualink.h" // L_handle_metro() typedef enum { METRO_STATUS_RUNNING , METRO_STATUS_STOPPED @@ -97,7 +97,7 @@ void Metro_set_stage( int ix, int stage ) static void Metro_bang( int ix ) { - L_queue_metro( ix, metros[ix].stage ); + // L_queue_metro( ix, metros[ix].stage ); metros[ix].stage++; if( metros[ix].stage == 0x7FFFFFFF ){ metros[ix].stage = 0x7FFFFFFE; } // overflow if( metros[ix].count >= 0 ){ // negative values are infinite diff --git a/lib/repl.c b/lib/repl.c deleted file mode 100644 index e83af7e0..00000000 --- a/lib/repl.c +++ /dev/null @@ -1,221 +0,0 @@ -#include "repl.h" - -#include // malloc(), free() -#include // memcpy() -#include -#include - -#include // HAL_Delay() -#include "lib/flash.h" // Flash_write_(), Flash_which_userscript(), Flash_read() -#include "lib/caw.h" // Caw_send_raw(), Caw_send_luachunk(), Caw_send_luaerror() - -// types -typedef enum{ REPL_normal - , REPL_reception - , REPL_discard -} L_repl_mode; - -// global variables -lua_State* Lua; -L_repl_mode repl_mode = REPL_normal; -char new_script[USER_SCRIPT_SIZE]; // static alloc avoids malloc failures -uint16_t new_script_len; -static bool running_from_mem; -static char running_script_name[64]; - -// prototypes -static bool REPL_new_script_buffer( uint32_t len ); -static bool REPL_run_script( USERSCRIPT_t mode, char* buf, uint32_t len ); -static void REPL_receive_script( char* buf, uint32_t len, ErrorHandler_t errfn ); -static char* REPL_script_name_from_mem( char* dest, char* src, int max_len ); - -// public interface -void REPL_init( lua_State* lua ) -{ - Lua = lua; - running_from_mem = false; - - switch( Flash_which_user_script() ){ - case USERSCRIPT_Default: - REPL_run_script( USERSCRIPT_Default, NULL, 0 ); - break; - case USERSCRIPT_User: - { - uint16_t flash_len = Flash_read_user_scriptlen(); - REPL_new_script_buffer( flash_len ); - if( Flash_read_user_script( new_script ) - || !REPL_run_script( USERSCRIPT_User, new_script, flash_len ) ){ - printf("failed to load user script\n"); - Caw_send_luachunk("failed to load user script"); - } - break; - } - case USERSCRIPT_Clear: - REPL_run_script( USERSCRIPT_Clear, NULL, 0 ); - break; - } -} - -void REPL_begin_upload( void ) -{ - REPL_reset(); // free up memory - if( REPL_new_script_buffer( USER_SCRIPT_SIZE ) ){ - repl_mode = REPL_reception; - } else { - repl_mode = REPL_discard; - } -} - -void REPL_upload( int flash ) -{ - if( repl_mode == REPL_discard ){ - Caw_send_luachunk("upload failed, returning to normal mode"); - } else { - if( REPL_run_script( USERSCRIPT_User - , new_script - , new_script_len ) ){ // successful load - if( flash ){ - // TODO if we're setting init() should check it doesn't crash - if( Flash_write_user_script( new_script - , new_script_len - ) ){ - printf("flash write failed\n"); - Caw_send_luachunk("User script upload failed!"); - } else { - printf("script saved, len: %i\n", new_script_len); - Caw_send_luachunk("User script updated."); - running_from_mem = false; - REPL_print_script_name(); - Lua_crowbegin(); - } - } else { - running_from_mem = true; - REPL_print_script_name(); - Lua_crowbegin(); - } - } else { - Caw_send_luachunk("User script evaluation failed."); - } - } - repl_mode = REPL_normal; -} - -void REPL_clear_script( void ) -{ - REPL_reset(); - Flash_clear_user_script(); - running_from_mem = false; - REPL_run_script( USERSCRIPT_Clear, NULL, 0 ); - Caw_send_luachunk("User script cleared."); - REPL_print_script_name(); - Lua_crowbegin(); -} - -void REPL_default_script( void ) -{ - REPL_reset(); - Flash_default_user_script(); - running_from_mem = false; - REPL_run_script( USERSCRIPT_Default, NULL, 0 ); - Caw_send_luachunk("Using default script."); - REPL_print_script_name(); - Lua_crowbegin(); -} - -void REPL_reset( void ) -{ - Lua = Lua_Reset(); -} - -bool REPL_run_script( USERSCRIPT_t mode, char* buf, uint32_t len ) -{ - switch (mode) - { - case USERSCRIPT_Default: - Lua_load_default_script(); - strcpy( running_script_name, "Running: First.lua" ); - break; - case USERSCRIPT_User: - if ( Lua_eval( Lua, buf, len, "=userscript" ) ){ - return false; - } - strcpy( running_script_name, "Running: " ); - REPL_script_name_from_mem( &running_script_name[9], buf, 64-10); - break; - case USERSCRIPT_Clear: - strcpy( running_script_name, "No user script." ); - break; - } - return true; -} - -void REPL_eval( char* buf, uint32_t len, ErrorHandler_t errfn ) -{ - if( repl_mode == REPL_normal ){ - if(Lua_eval( Lua, buf - , len - , "=repl" - )){ - printf("!eval\n"); - } - } else if( repl_mode == REPL_reception ){ // REPL_reception - REPL_receive_script( buf, len, errfn ); - } // else REPL_discard -} - -void REPL_print_script( void ) -{ - if( !running_from_mem && Flash_which_user_script() == USERSCRIPT_User ){ - uint16_t length = Flash_read_user_scriptlen(); - char* addr = Flash_read_user_scriptaddr(); - const int chunk = 0x200; - while( length > chunk ){ - Caw_send_raw( (uint8_t*)addr, chunk ); - length -= chunk; - addr += chunk; - HAL_Delay(3); // wait for usb tx - } - Caw_send_raw( (uint8_t*)addr, length ); - } else { - REPL_print_script_name(); - } -} - -void REPL_print_script_name( void ) -{ - Caw_send_luachunk( running_script_name ); -} - -// private funcs -static void REPL_receive_script( char* buf, uint32_t len, ErrorHandler_t errfn ) -{ - if( new_script_len + len >= USER_SCRIPT_SIZE ){ - Caw_send_luachunk("!ERROR! Script is too long."); - repl_mode = REPL_discard; - } else { - memcpy( &new_script[new_script_len], buf, len ); - new_script_len += len; - } -} - -static bool REPL_new_script_buffer( uint32_t len ) -{ - new_script_len = 0; // reset counter as the buffer is empty - return true; -} - -static char* REPL_script_name_from_mem( char* dest, char* src, int max_len ) -{ - while( *src == '-' ){ src++; } // skip commments - while( *src == ' ' ){ src++; } // skip spaces - char* linebreak = strchr( src, '\n' ); - int len = linebreak ? (int)(linebreak - src) : max_len; - if( len >= max_len ){ len = max_len - 1; } -// disable this warning bc we take care to null terminate our string -// *dest is a static 64byte array, so there's always room for it -#pragma GCC diagnostic ignored "-Wstringop-truncation" - strncpy( dest, src, len ); -#pragma GCC diagnostic pop - dest[len] = '\0'; - return dest; -} diff --git a/lib/repl.h b/lib/repl.h deleted file mode 100644 index 32a64966..00000000 --- a/lib/repl.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -// lua_State* -#include "../submodules/lua/src/lua.h" -#include "../submodules/lua/src/lauxlib.h" -#include "../submodules/lua/src/lualib.h" - -#include "lualink.h" // ErrorHandler_t, Lua_eval(), Lua_load_default_script() - -void REPL_init( lua_State* lua ); -void REPL_begin_upload( void ); -void REPL_upload( int flash ); -void REPL_clear_script( void ); -void REPL_default_script( void ); -void REPL_reset( void ); - -void REPL_eval( char* buf, uint32_t len, ErrorHandler_t errfn ); -void REPL_print_script( void ); -void REPL_print_script_name( void ); diff --git a/ll/adc.c b/ll/adc.c new file mode 100644 index 00000000..370e84cc --- /dev/null +++ b/ll/adc.c @@ -0,0 +1,256 @@ +#include "adc.h" + +#include +// #include // HAL_Delay() + +#include "interrupts.h" +#include "../lib/caw.h" + +static ADC_HandleTypeDef AdcHandle; +static ADC_HandleTypeDef AdcHandle2; +static ADC_ChannelConfTypeDef sConfig; + +#define ADC_CHANNELS 3 +#define ADC_BUFFERS 2 +static volatile uint16_t adc_raw[ADC_CHANNELS*ADC_BUFFERS*2]; // 6 channels, +static volatile uint16_t* adc_raw2 = &adc_raw[ADC_CHANNELS*ADC_BUFFERS*1]; // second 3 channels + + +static void start_conversion(void); + +void ADC_Init(void){ + AdcHandle.Instance = ADC1; + HAL_ADC_DeInit(&AdcHandle); + + AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; + AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; + AdcHandle.Init.ScanConvMode = ADC_SCAN_ENABLE; + AdcHandle.Init.ContinuousConvMode = ENABLE; // i think disable + AdcHandle.Init.NbrOfConversion = 3; // scan all 5 chans on ADC1 + AdcHandle.Init.DiscontinuousConvMode = DISABLE; // i think enable + AdcHandle.Init.NbrOfDiscConversion = 3; + AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; + AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + AdcHandle.Init.DMAContinuousRequests = ENABLE; + AdcHandle.Init.EOCSelection = ADC_EOC_SEQ_CONV; + + if( HAL_ADC_Init( &AdcHandle ) != HAL_OK ){ + Caw_printf("HAL_ADC_Init failed\n"); + } + + // Channel configuration + sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; + // sConfig.SamplingTime = ADC_SAMPLETIME_144CYCLES; + sConfig.Offset = 0; + + sConfig.Channel = ADC_CHANNEL_7; + sConfig.Rank = 1; + if( HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + sConfig.Channel = ADC_CHANNEL_8; + sConfig.Rank = 2; + if( HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + sConfig.Channel = ADC_CHANNEL_9; + sConfig.Rank = 3; + if( HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + + + + AdcHandle2.Instance = ADC2; + HAL_ADC_DeInit(&AdcHandle2); + + AdcHandle2.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; + AdcHandle2.Init.Resolution = ADC_RESOLUTION_12B; + AdcHandle2.Init.ScanConvMode = ADC_SCAN_ENABLE; + AdcHandle2.Init.ContinuousConvMode = ENABLE; // i think disable + AdcHandle2.Init.NbrOfConversion = 3; // scan all 5 chans on ADC1 + AdcHandle2.Init.DiscontinuousConvMode = DISABLE; // i think enable + AdcHandle2.Init.NbrOfDiscConversion = 3; + AdcHandle2.Init.ExternalTrigConv = ADC_SOFTWARE_START; + AdcHandle2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + AdcHandle2.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + AdcHandle2.Init.DataAlign = ADC_DATAALIGN_RIGHT; + AdcHandle2.Init.DMAContinuousRequests = ENABLE; + AdcHandle2.Init.EOCSelection = ADC_EOC_SEQ_CONV; + + if( HAL_ADC_Init( &AdcHandle2 ) != HAL_OK ){ + Caw_printf("HAL_ADC_Init2 failed\n"); + } + + sConfig.Channel = ADC_CHANNEL_14; + sConfig.Rank = 1; + if( HAL_ADC_ConfigChannel(&AdcHandle2, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + sConfig.Channel = ADC_CHANNEL_5; + sConfig.Rank = 2; + if( HAL_ADC_ConfigChannel(&AdcHandle2, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + sConfig.Channel = ADC_CHANNEL_6; + sConfig.Rank = 3; + if( HAL_ADC_ConfigChannel(&AdcHandle2, &sConfig) != HAL_OK ) + Caw_printf("HAL_ADC_ConfigChannel failed\n"); + + + start_conversion(); +} + +static void start_conversion(void){ + if( HAL_ADC_Start_DMA( &AdcHandle + , (uint32_t*)adc_raw + , ADC_CHANNELS*ADC_BUFFERS + ) != HAL_OK ){ + Caw_printf("HAL_ADC_Start_DMA failed, retrying..\n"); + // HAL_Delay(10); + if( HAL_ADC_Start_DMA( &AdcHandle + , (uint32_t*)adc_raw + , ADC_CHANNELS*ADC_BUFFERS + ) != HAL_OK ){ + Caw_printf("HAL_ADC_Start_DMA failed again, ignoring\n"); + return; + } + } + + if( HAL_ADC_Start_DMA( &AdcHandle2 + , (uint32_t*)adc_raw2 + , ADC_CHANNELS*ADC_BUFFERS + ) != HAL_OK ){ + Caw_printf("HAL_ADC_Start_DMA failed, retrying..\n"); + // HAL_Delay(10); + if( HAL_ADC_Start_DMA( &AdcHandle2 + , (uint32_t*)adc_raw2 + , ADC_CHANNELS*ADC_BUFFERS + ) != HAL_OK ){ + Caw_printf("HAL_ADC_Start_DMA failed again, ignoring\n"); + return; + } + } + // Caw_printf("conversion started\n\r"); +} + +static DMA_HandleTypeDef hdma_adc; +static DMA_HandleTypeDef hdma_adc2; +void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc){ + GPIO_InitTypeDef gpio; + + if(hadc == &AdcHandle){ // ADC1 + __HAL_RCC_ADC1_CLK_ENABLE(); // just using ADC1 for now + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + gpio.Mode = GPIO_MODE_ANALOG; + gpio.Pull = GPIO_NOPULL; + + // ADC1,2,3 + gpio.Pin = GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &gpio); + gpio.Pin = GPIO_PIN_0 | GPIO_PIN_1; + HAL_GPIO_Init(GPIOB, &gpio); + + // ADC1: d2.s0.c0, d2.s4.c0 + hdma_adc.Instance = DMA2_Stream4; // or DMA2_stream0 + + hdma_adc.Init.Channel = DMA_CHANNEL_0; + hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_adc.Init.MemInc = DMA_MINC_ENABLE; + hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_adc.Init.Mode = DMA_CIRCULAR; + hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; + hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; + hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE; + + HAL_DMA_DeInit(&hdma_adc); + HAL_DMA_Init(&hdma_adc); + + __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc); + + HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, ADC_IRQPriority, 1); + HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn); + + } else if(hadc == &AdcHandle2){ + __HAL_RCC_ADC2_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + gpio.Mode = GPIO_MODE_ANALOG; + gpio.Pull = GPIO_NOPULL; + + // ADC4,5,6 + gpio.Pin = GPIO_PIN_4; + HAL_GPIO_Init(GPIOC, &gpio); + gpio.Pin = GPIO_PIN_5 | GPIO_PIN_6; + HAL_GPIO_Init(GPIOA, &gpio); + + // ADC2: d2.s2.c1, d2.s3.c1 + hdma_adc2.Instance = DMA2_Stream2; // Stream2/3, Channel1 + + hdma_adc2.Init.Channel = DMA_CHANNEL_1; + hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_adc2.Init.MemInc = DMA_MINC_ENABLE; + hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_adc2.Init.Mode = DMA_CIRCULAR; + hdma_adc2.Init.Priority = DMA_PRIORITY_HIGH; + hdma_adc2.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_adc2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; + hdma_adc2.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_adc2.Init.PeriphBurst = DMA_PBURST_SINGLE; + + HAL_DMA_DeInit(&hdma_adc2); + HAL_DMA_Init(&hdma_adc2); + + __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc2); + + HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, ADC_IRQPriority, 2); + HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); + } +} + +static int read_half[2] = {0,0}; +uint16_t ADC_get(int chan){ // inversion & bipolar shaping + // 1,2,3,1,2,3,4,5,6,4,5,6 + if(chan<3){ + chan += read_half[0] * ADC_CHANNELS; + } else { + chan -= ADC_CHANNELS; // 3-5 down to 0-2 + chan += read_half[1] * ADC_CHANNELS; // +0 or +3 -> 0-2 / 3-5 + chan += ADC_CHANNELS * 2; // += 6 -> 6-8 / 9-11 + } + return adc_raw[chan]; +} + + +//// private +void DMA2_Stream4_IRQHandler(void){ + HAL_DMA_IRQHandler(AdcHandle.DMA_Handle); +} + +void DMA2_Stream2_IRQHandler(void){ + HAL_DMA_IRQHandler(AdcHandle2.DMA_Handle); +} + +void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc){ + if(hadc == &AdcHandle){ + read_half[0] = 0; + } else if(hadc == &AdcHandle2){ + read_half[1] = 0; + } +} +void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ + if(hadc == &AdcHandle){ + read_half[0] = 1; + } else if(hadc == &AdcHandle2){ + read_half[1] = 1; + } +} +void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc){ + Caw_printf("adc error\n\r"); +} diff --git a/ll/adc.h b/ll/adc.h new file mode 100644 index 00000000..52f15589 --- /dev/null +++ b/ll/adc.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +void ADC_Init(void); + +uint16_t ADC_get(int chan); + +// hardware callback integrations +void DMA2_Stream4_IRQHandler(void); +void DMA2_Stream2_IRQHandler(void); +void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc); +void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc); +void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc); diff --git a/ll/adda.c b/ll/adda.c index fb7647e9..704f6703 100644 --- a/ll/adda.c +++ b/ll/adda.c @@ -1,159 +1,44 @@ #include "adda.h" -#include -#include - -#include "debug_pin.h" -#include "ads131.h" -#include "dac8565.h" - -#include "../lib/flash.h" // FLASH_*_t -#include "cal_ll.h" // CAL_LL_Init(), -#include "../lib/slopes.h" // S_toward() -#include "../lib/caw.h" // Caw_send_raw - -typedef struct { - float shift; - float scale; -} CAL_chan_t; - -typedef struct { - CAL_chan_t adc[2]; - CAL_chan_t dac[4]; -} CAL_t; - -static CAL_t cal; -static void CAL_ReadFlash( void ); - - -uint16_t ADDA_Init( int adc_timer_ix ) -{ - ADC_Init( ADDA_BLOCK_SIZE - , ADDA_ADC_CHAN_COUNT - , adc_timer_ix - ); - DAC_Init( ADDA_BLOCK_SIZE - , ADDA_DAC_CHAN_COUNT - ); - CAL_LL_Init(); - CAL_ReadFlash(); - return ADDA_BLOCK_SIZE; -} - -void ADDA_Start( void ) -{ - DAC_Start(); -} - -void ADDA_BlockProcess( uint32_t* dac_pickle_ptr ) -{ - IO_block_t b = { .size = ADDA_BLOCK_SIZE }; - ADC_UnpickleBlock( b.in[0] - , ADDA_BLOCK_SIZE - ); - IO_BlockProcess( &b ); - DAC_PickleBlock( dac_pickle_ptr - , b.out[0] - , ADDA_BLOCK_SIZE - ); -} - -float ADDA_GetADCValue( uint8_t channel ) -{ - return ADC_GetValue( channel ); -} - -__weak IO_block_t* IO_BlockProcess( IO_block_t* b ) -{ - for( uint16_t i=0; i<(b->size); i++ ){ - b->out[0][i] = b->in[0][i]; - b->out[1][i] = b->in[1][i]; - b->out[2][i] = 2.0; - b->out[3][i] = 3.0; - } - return b; -} - - -//////////////////////////////////////////// -// Calibration - -void CAL_WriteFlash( void ) -{ - if( Flash_write_calibration( (uint8_t*)(&cal) - , sizeof(CAL_chan_t) * (2+4) - ) ){ - char msg[] = "Error saving Cal data to flash!\n"; - Caw_send_raw( (uint8_t*)msg, strlen(msg) ); - printf(msg); - } else { - char msg[] = "Calibration ok!\n\r"; - Caw_send_raw( (uint8_t*)msg, strlen(msg) ); - printf(msg); - } -} - -void CAL_Set( int chan, CAL_Param_t param, float val ) -{ - if(chan >= 1 && chan <= 2){ // adc - if(param == CAL_Offset){ - cal.adc[chan-1].shift = val; - ADC_CalibrateShift(chan-1, val); - } else { - cal.adc[chan-1].scale = val; - ADC_CalibrateScalar(chan-1, val); - } - } else if( chan >= 3 && chan <= 6){ // dac - if(param == CAL_Offset){ - cal.dac[chan-3].shift = val; - DAC_CalibrateOffset(chan-3, val); - } else { - cal.dac[chan-3].scale = val; - DAC_CalibrateScalar(chan-3, val); - } - } -} - -float CAL_Get( int chan, CAL_Param_t param ) -{ - if(chan >= 1 && chan <= 2){ // adc - if(param == CAL_Offset){ - return cal.adc[chan-1].shift; - } else { - return cal.adc[chan-1].scale; +// dest is an array of u32 sample slots +// output should be organized: 0,8,1,9,2,10 .. 7,15 +// with bsize of these in series +static uint32_t stepper[16] = {0}; + +static uint32_t vals[6] = {0}; + +void ADDA_BlockProcess(uint32_t* dest, int bsize) +{ + // IO_block_t b = { .size = ADDA_BLOCK_SIZE }; + // ADC_UnpickleBlock( b.in[0] + // , ADDA_BLOCK_SIZE + // ); + // IO_BlockProcess( &b ); + // DAC_PickleBlock( dac_pickle_ptr + // , b.out[0] + // , ADDA_BLOCK_SIZE + // ); + for(int i=0; i>3; // 1 if an upper set. upper 8 are 1 step ahead of lower + int ix = i*16; // for each sample, step forward by 16 samples (there are 16 channels) + dest[jj+jx+ix] = (jj<<11) | (samp & 0xfff); // hard cut values to 12bit range } - } else if( chan >= 3 && chan <= 6){ //dac - if(param == CAL_Offset){ - return cal.dac[chan-3].shift; - } else { - return cal.dac[chan-3].scale; - } - } else { return 0.0; } -} - -static void CAL_Defaults( void ) -{ - for( int j=1; j<7; j++ ){ - CAL_Set(j, CAL_Offset, 0.0); - CAL_Set(j, CAL_Scale, 1.0); } } -static void CAL_ReadFlash( void ) -{ - if( !Flash_read_calibration( (uint8_t*)(&cal) - , sizeof(CAL_chan_t) * (2+4) - ) ){ - for( int j=0; j<2; j++ ){ - ADC_CalibrateShift( j, cal.adc[j].shift ); - ADC_CalibrateScalar( j, cal.adc[j].scale ); - } - for( int j=0; j<4; j++ ){ - DAC_CalibrateOffset( j, cal.dac[j].shift ); - DAC_CalibrateScalar( j, cal.dac[j].scale ); - } - } else { - printf("not yet calibrated\n"); - CAL_Defaults(); - } +void ADDA_set_val(int ch, uint32_t val){ + if((ch>=0) && (ch<6)){ + vals[ch] = val & 0xfff; + } } diff --git a/ll/adda.h b/ll/adda.h index 3079f1be..05120f95 100644 --- a/ll/adda.h +++ b/ll/adda.h @@ -2,29 +2,5 @@ #include -#define ADDA_BLOCK_SIZE 32 -#define ADDA_DAC_CHAN_COUNT 4 -#define ADDA_ADC_CHAN_COUNT 2 - -typedef struct{ - float in[ ADDA_ADC_CHAN_COUNT][ADDA_BLOCK_SIZE]; - float out[ADDA_DAC_CHAN_COUNT][ADDA_BLOCK_SIZE]; - uint16_t size; -} IO_block_t; - -uint16_t ADDA_Init( int adc_timer_ix ); -void ADDA_Start( void ); -void ADDA_BlockProcess( uint32_t* dac_pickle_ptr ); - -float ADDA_GetADCValue( uint8_t channel ); - -// __weak definition -// Implement this in library code -// It handles the block-processing of the IO! -IO_block_t* IO_BlockProcess( IO_block_t* b ); - -// calibration -typedef enum{ CAL_Offset, CAL_Scale } CAL_Param_t; -void CAL_WriteFlash( void ); -void CAL_Set( int chan, CAL_Param_t param, float val ); -float CAL_Get( int chan, CAL_Param_t param ); +void ADDA_BlockProcess(uint32_t* dest, int bsize); +void ADDA_set_val(int ch, uint32_t val); diff --git a/ll/ads131.c b/ll/ads131.c deleted file mode 100644 index de7d3261..00000000 --- a/ll/ads131.c +++ /dev/null @@ -1,519 +0,0 @@ -#include "ads131.h" - -#include -#include - -#include "timers.h" -#include "debug_pin.h" - -#define ADC_FRAMES 3 // status word, plus 2 channels -#define ADC_BUF_SIZE (ADS_DATAWORDSIZE * ADC_FRAMES) -//#define ADC_BUF_SIZE (ADC_FRAMES) - -#define NSS_DELAY 10000 -#define DELAY_usec(u) \ - do{ for( volatile int i=0; i cast to float -> scale -> shift - float once = ((float)((int16_t*)aRxBuffer)[j+1]) // +1 past status byte - * adc_calibrated_scalar[j] - + adc_calibrated_shift[j]; - for( uint16_t i=0; i> 8; - if( error != 0 ){ // fault handler - retval = 1; - if( error & 0x2 ){} // Data ready fault - if( error & 0x4 ){ // Resync fault - //printf("sync\n"); - } - if( error & 0x8 ){ // Watchdog timer - printf("watchdog\n"); - } - if( error & 0x10 ){ // ADC input fault - //printf("adc_p: %i\n", ADS_Reg( ADS_READ_REG | ADS_STAT_P, 0 )); - //printf("adc_n: %i\n", ADS_Reg( ADS_READ_REG | ADS_STAT_N, 0 )); - } - if( error & 0x20 ){ // SPI fault - //printf("spi: %i\n", ADS_Reg( ADS_READ_REG | ADS_STAT_S, 0 )); - } - if( error & 0x40 ){ // Command fault - //printf("ADS bad_cmd\n"); - return 2; - } - } - return retval; -} -void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) -{ - printf("ads spi_error\n"); - // pull NSS high to cancel any ongoing transmission - HAL_GPIO_WritePin( SPIa_NSS_GPIO_PORT, SPIa_NSS_PIN, 1 ); -} - -void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) -{ - //printf("txrx-cb\n"); - // signal end of transmission by pulling NSS high - HAL_GPIO_WritePin( SPIa_NSS_GPIO_PORT, SPIa_NSS_PIN, 1 ); -} - -void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) -{ - //printf("rx-cb\n"); - // signal end of transmission by pulling NSS high - //_ADC_CheckErrors( aRxBuffer[0] ); - HAL_GPIO_WritePin( SPIa_NSS_GPIO_PORT, SPIa_NSS_PIN, 1 ); -} - -void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) -{ - static DMA_HandleTypeDef hdma_rx; - static DMA_HandleTypeDef hdma_tx; - - GPIO_InitTypeDef GPIO_InitStruct; - - SPIa_NSS_GPIO_CLK_ENABLE(); - SPIa_SCK_GPIO_CLK_ENABLE(); - SPIa_MISO_GPIO_CLK_ENABLE(); - SPIa_MOSI_GPIO_CLK_ENABLE(); - - SPIa_NRST_GPIO_CLK_ENABLE(); - - SPIa_CLK_ENABLE(); - - SPIa_DMAx_CLK_ENABLE(); - - // GPIO pins - GPIO_InitStruct.Pin = SPIa_SCK_PIN; - GPIO_InitStruct.Speed = GPIO_SPEED_FAST; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Alternate = SPIa_SCK_AF; - HAL_GPIO_Init(SPIa_SCK_GPIO_PORT, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = SPIa_MISO_PIN; - GPIO_InitStruct.Alternate = SPIa_MISO_AF; - HAL_GPIO_Init(SPIa_MISO_GPIO_PORT, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = SPIa_MOSI_PIN; - GPIO_InitStruct.Alternate = SPIa_MOSI_AF; - HAL_GPIO_Init(SPIa_MOSI_GPIO_PORT, &GPIO_InitStruct); - - // NSS & NRST handled manually - GPIO_InitStruct.Pin = SPIa_NSS_PIN; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - HAL_GPIO_Init(SPIa_NSS_GPIO_PORT, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = SPIa_NRST_PIN; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - HAL_GPIO_Init(SPIa_NRST_GPIO_PORT, &GPIO_InitStruct); - - // pull NSS high immediately (resting state) - HAL_GPIO_WritePin( SPIa_NRST_GPIO_PORT, SPIa_NRST_PIN, 1 ); - HAL_GPIO_WritePin( SPIa_NSS_GPIO_PORT, SPIa_NSS_PIN, 1 ); - - // DMA Streams - hdma_tx.Instance = SPIa_TX_DMA_STREAM; - - hdma_tx.Init.Channel = SPIa_TX_DMA_CHANNEL; - hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; - hdma_tx.Init.Mode = DMA_NORMAL; - hdma_tx.Init.Priority = DMA_PRIORITY_LOW; - hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_tx.Init.MemBurst = DMA_MBURST_INC4; - hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; - - HAL_DMA_Init(&hdma_tx); - - // Associate SPI w/ DMA - __HAL_LINKDMA(hspi, hdmatx, hdma_tx); - - // Reception: - hdma_rx.Instance = SPIa_RX_DMA_STREAM; - - hdma_rx.Init.Channel = SPIa_RX_DMA_CHANNEL; - hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; - hdma_rx.Init.Mode = DMA_NORMAL; - hdma_rx.Init.Priority = DMA_PRIORITY_LOW; - hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_rx.Init.MemBurst = DMA_MBURST_INC4; - hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4; - - HAL_DMA_Init(&hdma_rx); - - // Associate SPI w/ DMA - __HAL_LINKDMA(hspi, hdmarx, hdma_rx); - - - // DMA Priority (should be below IO, but above main process) - HAL_NVIC_SetPriority( SPIa_DMA_TX_IRQn - , SPIa_DMA_TX_IRQPriority - , SPIa_DMA_TX_IRQSubPriority - ); - HAL_NVIC_EnableIRQ( SPIa_DMA_TX_IRQn ); - - HAL_NVIC_SetPriority( SPIa_DMA_RX_IRQn - , SPIa_DMA_RX_IRQPriority - , SPIa_DMA_RX_IRQSubPriority - ); - HAL_NVIC_EnableIRQ( SPIa_DMA_RX_IRQn ); - - // Must be lower priority than the above DMA - HAL_NVIC_SetPriority( SPIa_IRQn - , SPIa_IRQPriority - , SPIa_IRQSubPriority - ); - HAL_NVIC_EnableIRQ( SPIa_IRQn ); -} - -void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi) -{ - static DMA_HandleTypeDef hdma_rx; - static DMA_HandleTypeDef hdma_tx; - - SPIa_FORCE_RESET(); - SPIa_RELEASE_RESET(); - - HAL_GPIO_DeInit(SPIa_SCK_GPIO_PORT, SPIa_SCK_PIN); - HAL_GPIO_DeInit(SPIa_MISO_GPIO_PORT, SPIa_MISO_PIN); - HAL_GPIO_DeInit(SPIa_MOSI_GPIO_PORT, SPIa_MOSI_PIN); - HAL_GPIO_DeInit(SPIa_NSS_GPIO_PORT, SPIa_NSS_PIN); - - HAL_DMA_DeInit(&hdma_tx); - HAL_DMA_DeInit(&hdma_rx); - - HAL_NVIC_DisableIRQ(SPIa_DMA_TX_IRQn); - HAL_NVIC_DisableIRQ(SPIa_DMA_RX_IRQn); - HAL_NVIC_DisableIRQ(SPIa_IRQn); -} - -void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) -{ - GPIO_InitTypeDef GPIO_InitStruct; - TIMa_MCLK_GPIO_CLK_ENABLE(); - - TIMa_CLK_ENABLE(); - - GPIO_InitStruct.Pin = TIMa_MCLK_PIN; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FAST; - //GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Alternate = TIMa_MCLK_AF; - HAL_GPIO_Init(TIMa_MCLK_GPIO_PORT, &GPIO_InitStruct); -} - -void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef *htim) -{ - TIMa_FORCE_RESET(); - TIMa_RELEASE_RESET(); - - HAL_GPIO_DeInit(TIMa_MCLK_GPIO_PORT, TIMa_MCLK_PIN); -} - -void SPIa_DMA_RX_IRQHandler(void) -{ - HAL_DMA_IRQHandler(adc_spi.hdmarx); -} -void SPIa_DMA_TX_IRQHandler(void) -{ - HAL_DMA_IRQHandler(adc_spi.hdmatx); -} -void SPIa_IRQHandler(void) -{ - HAL_SPI_IRQHandler(&adc_spi); -} diff --git a/ll/ads131.h b/ll/ads131.h deleted file mode 100644 index c7098617..00000000 --- a/ll/ads131.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include -#include "interrupts.h" // ADC_IRQPriority - -// Defs for MCLK pin, using hardware timer -#define TIMa TIM2 -#define TIMa_CLK_ENABLE() __HAL_RCC_TIM2_CLK_ENABLE() - -#define TIMa_FORCE_RESET() __HAL_RCC_TIM2_FORCE_RESET() -#define TIMa_RELEASE_RESET() __HAL_RCC_TIM2_RELEASE_RESET() - -#define TIMa_MCLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() - -#define TIMa_MCLK_PIN GPIO_PIN_3 -#define TIMa_MCLK_GPIO_PORT GPIOA -#define TIMa_MCLK_AF GPIO_AF1_TIM2 // this is PWM AF -#define TIMa_CHANNEL TIM_CHANNEL_4 - -// Definition for SPIa clock resources -#define SPIa SPI1 -#define SPIa_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE() -#define SPIa_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() -#define SPIa_NSS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() -#define SPIa_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() -#define SPIa_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() -#define SPIa_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() - -#define SPIa_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET() -#define SPIa_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET() - -// Definition for SPIa Pins -#define SPIa_NSS_PIN GPIO_PIN_4 -#define SPIa_NSS_GPIO_PORT GPIOA -#define SPIa_SCK_PIN GPIO_PIN_5 -#define SPIa_SCK_GPIO_PORT GPIOA -#define SPIa_SCK_AF GPIO_AF5_SPI1 -#define SPIa_MISO_PIN GPIO_PIN_6 -#define SPIa_MISO_GPIO_PORT GPIOA -#define SPIa_MISO_AF GPIO_AF5_SPI1 -#define SPIa_MOSI_PIN GPIO_PIN_7 -#define SPIa_MOSI_GPIO_PORT GPIOA -#define SPIa_MOSI_AF GPIO_AF5_SPI1 - -#define SPIa_NRST_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() -#define SPIa_NRST_PIN GPIO_PIN_4 -#define SPIa_NRST_GPIO_PORT GPIOC - -// Definition for SPIa's DMA -#define SPIa_TX_DMA_CHANNEL DMA_CHANNEL_3 -#define SPIa_TX_DMA_STREAM DMA2_Stream3 -#define SPIa_RX_DMA_CHANNEL DMA_CHANNEL_3 -#define SPIa_RX_DMA_STREAM DMA2_Stream0 - -// Definition for SPIa's NVIC -#define SPIa_IRQn SPI1_IRQn -#define SPIa_IRQHandler SPI1_IRQHandler -#define SPIa_DMA_TX_IRQn DMA2_Stream3_IRQn -#define SPIa_DMA_RX_IRQn DMA2_Stream0_IRQn -#define SPIa_DMA_TX_IRQHandler DMA2_Stream3_IRQHandler -#define SPIa_DMA_RX_IRQHandler DMA2_Stream0_IRQHandler - -#define SPIa_IRQPriority ADC_IRQPriority -#define SPIa_IRQSubPriority 2 -#define SPIa_DMA_TX_IRQPriority ADC_IRQPriority -#define SPIa_DMA_TX_IRQSubPriority 1 -#define SPIa_DMA_RX_IRQPriority ADC_IRQPriority -#define SPIa_DMA_RX_IRQSubPriority 0 - -// ADS131 commands -#define ADS_READY 0xFF02 - -#define ADS_NULL 0x0 -#define ADS_RESET 0x0011 -#define ADS_STANDBY 0x0022 -#define ADS_WAKEUP 0x0033 -#define ADS_LOCK 0x0555 -#define ADS_UNLOCK 0x0655 -//#define ADS_UNLOCK 0x5506 - -#define ADS_READ_REG 0x20 -#define ADS_WRITE_REG 0x40 - -// ads131 status registers -#define ADS_STAT_1 0x02 -#define ADS_STAT_P 0x03 -#define ADS_STAT_N 0x04 -#define ADS_STAT_S 0x05 -#define ADS_ERROR_CNT 0x06 -#define ADS_STAT_M2 0x07 - -// ads131 user config registers -#define ADS_A_SYS_CFG 0x0B -#define ADS_D_SYS_CFG 0x0C -#define ADS_CLK1 0x0D -#define ADS_CLK2 0x0E -#define ADS_ADC_ENA 0x0F - -#define ADS_DATAWORDSIZE 0x2 // 16bit, pin M1 floats - -void ADC_Init( uint16_t bsize, uint8_t chan_count, int timer_ix ); - -//int32_t -uint16_t ADC_GetU16( uint8_t channel ); -void ADC_UnpickleBlock( float* unpickled - , uint16_t bsize - ); -float ADC_GetValue( uint8_t channel ); - -void ADC_CalibrateScalar( uint8_t channel, float scale ); -void ADC_CalibrateShift( uint8_t channel, float volts ); - -void SPIa_DMA_RX_IRQHandler(void); -void SPIa_DMA_TX_IRQHandler(void); -void SPIa_IRQHandler(void); - -void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi); -void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi); -void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi); - -void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi); -void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi); diff --git a/ll/dac108.c b/ll/dac108.c new file mode 100644 index 00000000..13b42401 --- /dev/null +++ b/ll/dac108.c @@ -0,0 +1,300 @@ +#include "dac108.h" + +#include +#include "stdlib.h" // malloc() +#include "adda.h" + +#define DAC_BUFFER_COUNT 2 // ping-pong + +// pointer to the malloc()d buffer from DAC_Init() +static uint16_t samp_count = 0; +static uint32_t* samples = NULL; +static int b_size = 0; + +static const uint16_t write_through_mode = 0b1001000000000000; + +#define _DMA_PDATA_ALIGN DMA_PDATAALIGN_WORD +#define _DMA_MDATA_ALIGN DMA_MDATAALIGN_WORD +#define _DMA_FIFO_THRESH DMA_FIFO_THRESHOLD_HALFFULL +#define _T_SAMPLES uint32_t* +#define _SAI_DATASIZE SAI_DATASIZE_16 +#define _SAI_FIRSTBIT SAI_FIRSTBIT_MSB +#define _SAI_CLOCKSTROBE SAI_CLOCKSTROBING_RISINGEDGE + +#define _FRAME_LENGTH ((16*2)+1) +#define _FRAME_ACTIVE_LENGTH 1 +#define _FRAME_FSDEFINTION SAI_FS_STARTFRAME +#define _FRAME_FSPOLARITY SAI_FS_ACTIVE_HIGH +#define _FRAME_FSOFFSET SAI_FS_BEFOREFIRSTBIT + +#define _SLOT_FIRSTBITOFFSET 0 +#define _SLOT_SIZE SAI_SLOTSIZE_16B +#define _SLOT_NUMBER 2 +#define _SLOT_ACTIVE (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1) + +static void sai_start_transmit(uint32_t* hwords, uint16_t count); +static void sai_init(void); + +void DAC_Init(uint16_t bsize, uint8_t chan_count){ + b_size = bsize; + sai_init(); + + // Create the sample buffer for DMA transfer + samp_count = DAC_BUFFER_COUNT * bsize * chan_count; // 512 + printf("samp_count %x\n\r", samp_count); + samples = malloc( sizeof(uint32_t) * samp_count ); // 1k + if(samples == NULL){ printf("!DAC_buffer\n"); } + // for( int i=0; i>1); + sai_start_transmit(samples, samp_count); // in terms of bytes? +} + +void DAC_CalibrateScalar( uint8_t channel, float scale ){ + // dac_calibrated_scalar[channel] = DAC_V_TO_U16 * scale; +} + +void DAC_CalibrateOffset( uint8_t channel, float volts ){ + // dac_calibrated_offset[channel] = volts; +} + +uint16_t lim_i32_u12( int32_t v ){ + return (uint16_t)((v > 0xfff) ? 0xfff : (v < 0) ? 0 : v); +} + +/* Does all the work converting a generic representation into serial packets + * Convert floats (representing volts) to u16 representation + * Interleave a block of each channel into a stream + * */ +// unpickled_data is arranged as blocks of bsize, * chan count +// pickled data needs to be interleaved sample-by-sample across all channels +void DAC_PickleBlock( uint32_t* dac_pickle_ptr + , float* unpickled_data + , uint16_t bsize + ) +{ + // TODO calibration (maybe not) + // for( uint8_t j=0; j<4; j++ ){ + // add_vf_f( &(unpickled_data[j*bsize]) + // , dac_calibrated_offset[j] + // , &(unpickled_data[j*bsize]) + // , bsize + // ); + // } + // for( int j=0; j +/-2048.f + // uint16_t vv = lim_i32_u12((int32_t)(DAC_ZERO_VOLTS - unpickled_data[0])); + // vv |= (7<<12); + // uint16_t* dpp = (uint16_t*)dac_pickle_ptr; + + + /* + for(int i=0; i<(ADDA_DAC_CHAN_COUNT * bsize); i++){ + // 0chan + 0 + // 1chan + 0 + // ... + // 0chan + 1 + // ? = weird scan through the buffer to interleave channels + int b_chan = i % ADDA_DAC_CHAN_COUNT; + int b_samp = i / ADDA_DAC_CHAN_COUNT; + // DAC_ZERO_VOLTS = 0x7ff (2047) + // dac_pickle_ptr[i] = vv | (b_chan << 12); + // dac_pickle_ptr[i] = vv; + dac_pickle_ptr[i] = lim_i32_u12((int32_t)(DAC_ZERO_VOLTS - unpickled_data[b_samp + bsize*b_chan])); + dac_pickle_ptr[i] |= b_chan << 12; + // dac_pickle_ptr[i] <<= 16; + // *dpp = lim_i32_u12((int32_t)(DAC_ZERO_VOLTS - unpickled_data[b_samp + bsize*b_chan])); + // *dpp |= b_chan << 12; + // dpp++; + } + */ +} + +static SAI_HandleTypeDef hsai_a; +static DMA_HandleTypeDef hdma_tx_a; + +static void sai_init(void){ + RCC_PeriphCLKInitTypeDef rcc; + rcc.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI; + + // here we configure for 3.072MHz + // ie 8 channels, 17bits, 22.5kHz sample rate + // rcc.PLLSAI.PLLSAIN = 384; + // rcc.PLLSAI.PLLSAIN = 192; + rcc.PLLSAI.PLLSAIN = 96; + rcc.PLLSAI.PLLSAIQ = 5; + rcc.PLLSAIDivQ = 25; + // see @ciel/tools/sai_pll_calculator.lua to configure + + HAL_RCCEx_PeriphCLKConfig(&rcc); + + // Initialize SAI + __HAL_SAI_RESET_HANDLE_STATE(&hsai_a); + + // block A + hsai_a.Instance = SAI2_Block_B; // TODO follow instance + __HAL_SAI_DISABLE(&hsai_a); + hsai_a.Init.AudioMode = SAI_MODEMASTER_TX; + hsai_a.Init.Synchro = SAI_ASYNCHRONOUS; + hsai_a.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + hsai_a.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; + hsai_a.Init.NoDivider = SAI_MASTERDIVIDER_DISABLE; + hsai_a.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + hsai_a.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K; // _48K or _96K or _192K + hsai_a.Init.Protocol = SAI_FREE_PROTOCOL; + hsai_a.Init.DataSize = _SAI_DATASIZE; + hsai_a.Init.FirstBit = _SAI_FIRSTBIT; + hsai_a.Init.ClockStrobing = _SAI_CLOCKSTROBE; // CONFIRM + + hsai_a.FrameInit.FrameLength = _FRAME_LENGTH; // ie data length plus 1 bit for FS sync pulse + hsai_a.FrameInit.ActiveFrameLength = _FRAME_ACTIVE_LENGTH; + hsai_a.FrameInit.FSDefinition = _FRAME_FSDEFINTION; + hsai_a.FrameInit.FSPolarity = _FRAME_FSPOLARITY; + hsai_a.FrameInit.FSOffset = _FRAME_FSOFFSET; // SAI_FS_FIRSTBIT + + hsai_a.SlotInit.FirstBitOffset = _SLOT_FIRSTBITOFFSET; // maybe 1? + hsai_a.SlotInit.SlotSize = _SLOT_SIZE; + hsai_a.SlotInit.SlotNumber = _SLOT_NUMBER; // ie. only 1 chip in sequence + hsai_a.SlotInit.SlotActive = _SLOT_ACTIVE; // each DAC chan needs it's own frame! + + if(HAL_SAI_Init(&hsai_a)){ + printf("sai init failed\n\r"); + return; + } + + // Enable SAI to generate clock used by audio driver + __HAL_SAI_ENABLE(&hsai_a); +} + +void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai){ + GPIO_InitTypeDef GPIO_Init; + GPIO_Init.Mode = GPIO_MODE_AF_PP; + GPIO_Init.Pull = GPIO_PULLUP; + GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + + __HAL_RCC_DMA2_CLK_ENABLE(); + __HAL_RCC_SAI2_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + GPIO_Init.Alternate = GPIO_AF10_SAI2; + GPIO_Init.Pin = GPIO_PIN_0; + HAL_GPIO_Init(GPIOA, &GPIO_Init); + GPIO_Init.Alternate = GPIO_AF8_SAI2; + GPIO_Init.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOA, &GPIO_Init); + GPIO_Init.Alternate = GPIO_AF8_SAI2; + GPIO_Init.Pin = GPIO_PIN_0; + HAL_GPIO_Init(GPIOC, &GPIO_Init); + + // Configure DMA used for SAI2_B + // d2.s6.c3 // alternates: 2.7.0 + hdma_tx_a.Init.Channel = DMA_CHANNEL_3; + hdma_tx_a.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tx_a.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tx_a.Init.MemInc = DMA_MINC_ENABLE; + hdma_tx_a.Init.PeriphDataAlignment = _DMA_PDATA_ALIGN; + // hdma_tx_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma_tx_a.Init.MemDataAlignment = _DMA_MDATA_ALIGN; + hdma_tx_a.Init.Mode = DMA_CIRCULAR; + hdma_tx_a.Init.Priority = DMA_PRIORITY_HIGH; + hdma_tx_a.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_tx_a.Init.FIFOThreshold = _DMA_FIFO_THRESH; + hdma_tx_a.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_tx_a.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_tx_a.Instance = DMA2_Stream6; + + // Bidirectionally link the DMA & SAI handles + __HAL_LINKDMA(hsai, hdmatx, hdma_tx_a); + + // Deinitialize the Stream for new transfer + HAL_DMA_DeInit(&hdma_tx_a); + + // Configure the DMA Stream + if( HAL_OK != HAL_DMA_Init(&hdma_tx_a) ){ + // debug(&debug, "HAL_DMA_Init failed"); + return; + } + + // Codec request triggers transfer & new frame calc + HAL_NVIC_SetPriority( DMA2_Stream6_IRQn + , DAC_IRQPriority + , 1 + ); + HAL_NVIC_EnableIRQ( DMA2_Stream6_IRQn ); +} + +void sai_start_transmit(_T_SAMPLES hwords, uint16_t count){ + if(HAL_SAI_Transmit_DMA(&hsai_a, (uint8_t*)hwords, count)){ + printf("sai transmit fail.\n\r"); + } +} + + + +// static int status = 0; +// DMA triggered by codec requesting more ADC! +void DMA2_Stream6_IRQHandler(void){ + // status ^= 1; + // TP_debug_led(0, status); + HAL_DMA_IRQHandler(&hdma_tx_a); + if(hdma_tx_a.ErrorCode != HAL_OK){ + // printf("sai dma err: 0x%0x\n\r", hdma_tx_a.ErrorCode); + printf("sai dma err\n\r"); + } +} + +static inline void callback(int offset){ + ADDA_BlockProcess(&samples[offset], b_size); +} + +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai){ callback(0); } +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai){ callback(samp_count>>1); } +// void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai){ callback(samp_count>>1); } +// void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai){ callback(0); } +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai){ + // printf("sai error 0x%x\n\r", hsai->ErrorCode); + printf("sai error"); +} diff --git a/ll/dac108.h b/ll/dac108.h new file mode 100644 index 00000000..74828ea8 --- /dev/null +++ b/ll/dac108.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "interrupts.h" // DAC_IRQPriority + +void DAC_Init( uint16_t bsize, uint8_t chan_count ); +void DAC_Start(void); + +void DAC_PickleBlock( uint32_t* dac_pickle_ptr + , float* unpickled_data + , uint16_t bsize + ); + +// new +void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai); + +void DMA2_Stream6_IRQHandler(void); +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai); +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai); +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai); diff --git a/ll/dac8565.c b/ll/dac8565.c index a8e8cf4a..d6244c39 100644 --- a/ll/dac8565.c +++ b/ll/dac8565.c @@ -1,5 +1,6 @@ #include "dac8565.h" +/* #include #include "stdlib.h" // malloc() #include "debug_pin.h" @@ -52,11 +53,7 @@ void DAC_Init( uint16_t bsize, uint8_t chan_count ) HAL_GPIO_WritePin( I2Sx_NRST_GPIO_PORT, I2Sx_NRST_PIN, 1 ); } -/* Initialize the DMA buffer to contain required metadata - * Each channel is initialized with its relevant SPI command - * The last channel latches all the new values to the outputs - * - * */ + void DAC_Start(void) { // prepare SPI packet metadata @@ -104,10 +101,7 @@ int32_t lim_i32_u16( int32_t v ) return (v > (int32_t)(uint16_t)0xFFFF) ? 0xFFFF : (v < (int32_t)0) ? 0 : v; } -/* Does all the work converting a generic representation into serial packets - * Convert floats (representing volts) to u16 representation - * Interleave a block of each channel into a stream - * */ + void DAC_PickleBlock( uint32_t* dac_pickle_ptr , float* unpickled_data , uint16_t bsize @@ -280,3 +274,5 @@ void I2Sx_IRQHandler(void) { HAL_I2S_IRQHandler(&dac_i2s); } + +*/ diff --git a/ll/debug_usart.c b/ll/debug_usart.c index 4991052e..d994a313 100644 --- a/ll/debug_usart.c +++ b/ll/debug_usart.c @@ -17,15 +17,15 @@ void U_Print(char* s, int len){ return; } void Debug_USART_Init( void ) { #ifndef TRACE // ie using USART to debug - handusart.Instance = DBG_USARTx; + // handusart.Instance = DBG_USARTx; - handusart.Init.BaudRate = DBG_USART_baud; - handusart.Init.WordLength = USART_WORDLENGTH_8B; - handusart.Init.StopBits = USART_STOPBITS_1; - handusart.Init.Parity = USART_PARITY_NONE; - handusart.Init.Mode = USART_MODE_TX; + // handusart.Init.BaudRate = DBG_USART_baud; + // handusart.Init.WordLength = USART_WORDLENGTH_8B; + // handusart.Init.StopBits = USART_STOPBITS_1; + // handusart.Init.Parity = USART_PARITY_NONE; + // handusart.Init.Mode = USART_MODE_TX; - HAL_USART_Init( &handusart ); + // HAL_USART_Init( &handusart ); #endif // TRACE str_buf = str_buffer_init( 511 ); // fifo for DMA buffer } @@ -105,18 +105,18 @@ void USARTx_IRQHandler( void ) // Communication Functions void U_PrintNow( void ) { -#ifndef TRACE - if( HAL_USART_GetState( &handusart ) == HAL_USART_STATE_READY - && !str_buffer_empty( str_buf ) ){ - BLOCK_IRQS( - uint16_t str_len = str_buffer_len( str_buf ); - HAL_USART_Transmit_DMA( &handusart - , (uint8_t*)str_buffer_dequeue( str_buf, str_len ) - , str_len - ); - ); - } -#endif // TRACE +// #ifndef TRACE +// if( HAL_USART_GetState( &handusart ) == HAL_USART_STATE_READY +// && !str_buffer_empty( str_buf ) ){ +// BLOCK_IRQS( +// uint16_t str_len = str_buffer_len( str_buf ); +// HAL_USART_Transmit_DMA( &handusart +// , (uint8_t*)str_buffer_dequeue( str_buf, str_len ) +// , str_len +// ); +// ); +// } +// #endif // TRACE } void U_Print(char* s, int len) diff --git a/ll/din.c b/ll/din.c new file mode 100644 index 00000000..ba15847b --- /dev/null +++ b/ll/din.c @@ -0,0 +1,36 @@ +#include "din.h" + +#include +#include + +typedef struct{ + GPIO_TypeDef* gpio; + uint32_t pin; +} Pin; + +static const Pin ds[3] = + {{.gpio = GPIOB, .pin = GPIO_PIN_12} + ,{.gpio = GPIOB, .pin = GPIO_PIN_13} + ,{.gpio = GPIOB, .pin = GPIO_PIN_14}}; + +static GPIO_InitTypeDef g; + +void din_init(void){ + __HAL_RCC_GPIOB_CLK_ENABLE(); + + g.Speed = GPIO_SPEED_HIGH; + g.Pull = GPIO_NOPULL; + g.Mode = GPIO_MODE_INPUT; + + for(int i=0; i<3; i++){ + Pin dx = ds[i]; + g.Pin = dx.pin; + HAL_GPIO_Init(dx.gpio, &g); + } +} + +int din_get(DINx ch){ + if(ch<0 || ch>=3){ printf("din_get(bad_channel)\n\r"); return -1; } // out of range + Pin dx = ds[ch]; + return (int)!HAL_GPIO_ReadPin(dx.gpio, dx.pin); // pins are inverted (active low) +} diff --git a/ll/din.h b/ll/din.h new file mode 100644 index 00000000..09765bbd --- /dev/null +++ b/ll/din.h @@ -0,0 +1,11 @@ +#pragma once + +typedef enum{ + DIN_RESET, + DIN_DOWN, + DIN_2UP +} DINx; + +void din_init(void); + +int din_get(DINx ch); diff --git a/ll/interrupts.h b/ll/interrupts.h index 02deba4b..939f4697 100644 --- a/ll/interrupts.h +++ b/ll/interrupts.h @@ -1,6 +1,6 @@ #pragma once -#define ADC_IRQPriority 1 +#define ADC_IRQPriority 5 #define I2C_Priority 2 #define MIDI_IRQPriority 3 #define USB_IRQPriority 4 diff --git a/ll/lights.c b/ll/lights.c new file mode 100644 index 00000000..4919b71b --- /dev/null +++ b/ll/lights.c @@ -0,0 +1,87 @@ +#include "lights.h" + +#include +#include + +typedef struct{ + GPIO_TypeDef* gpio; + uint32_t pin; +} Pin; + +static const Pin ls[12] = + {{.gpio = GPIOA, .pin = GPIO_PIN_15} + ,{.gpio = GPIOC, .pin = GPIO_PIN_10} + ,{.gpio = GPIOC, .pin = GPIO_PIN_11} + ,{.gpio = GPIOC, .pin = GPIO_PIN_12} + ,{.gpio = GPIOD, .pin = GPIO_PIN_2} + ,{.gpio = GPIOB, .pin = GPIO_PIN_3} + ,{.gpio = GPIOB, .pin = GPIO_PIN_4} + ,{.gpio = GPIOB, .pin = GPIO_PIN_5} + ,{.gpio = GPIOB, .pin = GPIO_PIN_6} + ,{.gpio = GPIOB, .pin = GPIO_PIN_7} + ,{.gpio = GPIOB, .pin = GPIO_PIN_8} + ,{.gpio = GPIOB, .pin = GPIO_PIN_9}}; + +static GPIO_InitTypeDef g; +void lights_init(void){ + // should use an abstracted library rather than this hack + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + // GPIO_InitTypeDef g; + g.Speed = GPIO_SPEED_LOW; + + // this is correct method for leds with current limit + // g.Pull = GPIO_NOPULL; + // g.Mode = GPIO_MODE_OUTPUT_PP; + + // HACK! + // here we use pullup as current source, leaving pins as inputs + g.Pull = GPIO_NOPULL; // ie. lights off + g.Mode = GPIO_MODE_INPUT; + + for(int i=0; i<12; i++){ + Pin lx = ls[i]; + g.Pin = lx.pin; + HAL_GPIO_Init(lx.gpio, &g); + } + + lights_all(0); +} + +void lights_all(int state){ + for(int i=0; i<12; i++){ + lights_set(i, state); + } +} + +// this is the only function that calls the LL layer +void lights_set(int ch, int state){ + if(ch<0 || ch>=12){ printf("lights_set(bad_channel)\n\r"); return; } // out of range + Pin lx = ls[ch]; + + // This is the correct method once we add current limiting resistors + HAL_GPIO_WritePin(lx.gpio, lx.pin, !!state); + + // HACK!!! + // here we use internal pullups in stm32 as current sources for leds + // this means the brightness is dim, but at least we don't burn out the leds w/o ilim Rs + g.Pin = lx.pin; + g.Pull = !state ? GPIO_NOPULL : GPIO_PULLUP; // pullup controls lit state + HAL_GPIO_Init(lx.gpio, &g); +} + +void lights_xset(int ch){ + lights_all(0); + lights_set(ch, 1); +} + +void lights_range(int min, int max, int state){ + if(min >= max){ printf("lights_range(min must be < max)\n\r"); return; } + lights_all(0); + for(int i=min; i next_flip // time to animate timer + if((time_now > next_flip) // time to animate timer || (do_flip && fast_blink)){ // xor event & USB connected // status_led_xor(); - HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_15); + HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_14); next_flip = time_now + (fast_blink ? 2000 : 500); do_flip = false; } @@ -38,10 +38,10 @@ void status_led_fast(LED_SPEED is_fast){ } void status_led_set(uint8_t is_on){ - HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, is_on); + HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, is_on); } void status_led_xor(void){ - // HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_15); + // HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_14); do_flip = true; } diff --git a/main.c b/main.c index 3041d709..4d12a24c 100755 --- a/main.c +++ b/main.c @@ -1,31 +1,44 @@ #include "ll/system.h" -#include "ll/debug_pin.h" -#include "ll/debug_usart.h" +// #include "ll/debug_pin.h" +// #include "ll/debug_usart.h" #include "ll/status_led.h" #include "syscalls.c" // printf() redirection -#include "lib/io.h" -#include "lib/events.h" +// #include "lib/io.h" +// #include "lib/events.h" #include "ll/timers.h" -#include "lib/metro.h" +// #include "lib/metro.h" #include "lib/clock.h" #include "lib/caw.h" -#include "lib/ii.h" -#include "ll/i2c_pullups.h" // i2c_hw_pullups_init -#include "ll/random.h" -#include "lib/lualink.h" -#include "lib/repl.h" +// #include "lib/ii.h" +// #include "ll/i2c_pullups.h" // i2c_hw_pullups_init +// #include "ll/random.h" #include "usbd/usbd_cdc_interface.h" // CDC_main_init() -#include "lib/bootloader.h" // bootloader_enter(), bootloader_restart() -#include "lib/flash.h" // Flash_clear_user_script() #include "stm32f7xx_it.h" // CPU_count; +#include "ll/lights.h" +#include "ll/din.h" +#include "ll/adc.h" +#include "ll/dac108.h" +#include "ll/adda.h" +/* +density, C4, 2_in14 +steps, A5, 2_in5 +rotate, A6, 2_in6 +fold, A7, 1_in7 +id, B0, 1_in8 +offset, B1, 1_in9 -int main(void) -{ +MOSI, A0, SAI2_SD_B, AF10 +SCK, A2, SAI2_SCK_B, AF8 +!SYNC, C0, SAI2_FS_B, AF8 +*/ + + +int main(void){ system_init(); // Debugging - Debug_Pin_Init(); + // Debug_Pin_Init(); Debug_USART_Init(); // ignored in TRACE mode // User-readable status led status_led_init(); @@ -34,56 +47,66 @@ int main(void) printf("\n\nhi from crow!\n"); + lights_init(); + lights_all(0); + + din_init(); + + ADC_Init(); + // Drivers int max_timers = Timer_Init(); - IO_Init( max_timers-2 ); // use second-last timer - IO_Start(); // must start IO before running lua init() script - events_init(); - Metro_Init( max_timers-2 ); // reserve 2 timers for USB & ADC + // IO_Init( max_timers-2 ); // use second-last timer + // IO_Start(); // must start IO before running lua init() script + // Metro_Init( max_timers-2 ); // reserve 2 timers for USB & ADC clock_init( 100 ); // TODO how to pass it the timer? Caw_Init( max_timers-1 ); // use last timer CDC_clear_buffers(); - i2c_hw_pullups_init(); // enable GPIO for v1.1 hardware pullups - ii_init( II_CROW ); - Random_Init(); + // i2c_hw_pullups_init(); // enable GPIO for v1.1 hardware pullups + // ii_init( II_CROW ); + // Random_Init(); - REPL_init( Lua_Init() ); - - REPL_print_script_name(); - Lua_crowbegin(); + DAC_Init(32, 16); // 32 samples per block, 16 channels + DAC_Start(); uint32_t last_tick = HAL_GetTick(); + int counter = 100; + uint8_t state = 0; + int l_count = 0; while(1){ CPU_count++; U_PrintNow(); - switch( Caw_try_receive() ){ // true on pressing 'enter' - case C_repl: REPL_eval( Caw_get_read() - , Caw_get_read_len() - , Caw_send_luaerror - ); break; - case C_boot: bootloader_enter(); break; - case C_startupload: REPL_begin_upload(); break; - case C_endupload: REPL_upload(0); break; - case C_flashupload: REPL_upload(1); break; - case C_restart: bootloader_restart(); break; - case C_print: REPL_print_script(); break; - case C_version: system_print_version(); break; - case C_identity: system_print_identity(); break; - case C_killlua: REPL_reset(); break; - case C_flashclear: REPL_clear_script(); break; - case C_loadFirst: REPL_default_script(); break; - default: break; // 'C_none' does nothing - } - Random_Update(); + Caw_try_receive(); // JUST DROP RX'D VALS + + // Random_Update(); uint32_t time_now = HAL_GetTick(); // for running a 1ms-interval tick if( last_tick != time_now ){ // called on 1ms interval last_tick = time_now; clock_update(time_now); - status_led_tick(time_now); + // status_led_tick(time_now); + counter--; + if(counter<=0){ + counter = 100; + state ^= 1; + status_led_set(state); + l_count++; + if(l_count >= 12) l_count = 0; + + int a = ADC_get(4); // raw 0~4095 value + a *= 12; // scale up to 12*4096 + a >>= 12; // divide by 4096 + lights_xset(a); + // Caw_printf("%i\n\r",a); + } + for(int i=0; i<6; i++){ + ADDA_set_val(i, ADC_get(i)); + } } - event_next(); // check/execute single event - ii_leader_process(); + // lights_set(0, din_get(DIN_RESET)); + // lights_set(1, din_get(DIN_DOWN)); + // lights_set(2, din_get(DIN_2UP)); + // ii_leader_process(); Caw_send_queued(); } } diff --git a/stm32f7xx_hal_conf.h b/stm32f7xx_hal_conf.h index de5de43c..a79a28e3 100644 --- a/stm32f7xx_hal_conf.h +++ b/stm32f7xx_hal_conf.h @@ -51,7 +51,7 @@ * @brief This is the list of modules to be used in the HAL driver */ #define HAL_MODULE_ENABLED -/*#define HAL_ADC_MODULE_ENABLED*/ +#define HAL_ADC_MODULE_ENABLED /*#define HAL_CAN_MODULE_ENABLED*/ /*#define HAL_CEC_MODULE_ENABLED*/ /*#define HAL_CRC_MODULE_ENABLED*/ @@ -78,7 +78,7 @@ #define HAL_RCC_MODULE_ENABLED #define HAL_RNG_MODULE_ENABLED /*#define HAL_RTC_MODULE_ENABLED*/ -/*#define HAL_SAI_MODULE_ENABLED*/ +#define HAL_SAI_MODULE_ENABLED /*#define HAL_SD_MODULE_ENABLED*/ /*#define HAL_SPDIFRX_MODULE_ENABLED*/ #define HAL_SPI_MODULE_ENABLED