///////////////////////////////////////////////////////////////////////////// //! Starts a new transfer. If this function is called during an ongoing //! transfer, we wait until it has been finished and setup the new transfer //! \param[in] transfer type:<BR> //! <UL> //! <LI>IIC_Read: a common Read transfer //! <LI>IIC_Write: a common Write transfer //! <LI>IIC_Read_AbortIfFirstByteIs0: used to poll MBHP_IIC_MIDI: aborts transfer //! if the first received byte is 0 //! <LI>IIC_Write_WithoutStop: don't send stop condition after transfer to allow //! a restart condition (e.g. used to access EEPROMs) //! \param[in] iic_port the IIC port (0..MIOS32_IIC_NUM-1) //! \param[in] address of IIC device (bit 0 always cleared) //! \param[in] *buffer pointer to transmit/receive buffer //! \param[in] len number of bytes which should be transmitted/received //! \return 0 no error //! \return < 0 on errors, if MIOS32_IIC_ERROR_PREV_OFFSET is added, the previous //! transfer got an error (the previous task didn't use \ref MIOS32_IIC_TransferWait //! to poll the transfer state) //! \note Note that the semaphore will be released automatically after an error //! (MIOS32_IIC_TransferBegin() has to be called again) ///////////////////////////////////////////////////////////////////////////// s32 MIOS32_IIC_Transfer(u8 iic_port, mios32_iic_transfer_t transfer, u8 address, u8 *buffer, u16 len) { iic_rec_t *iicx = &iic_rec[iic_port];// simplify addressing of record s32 error; if( iic_port >= MIOS32_IIC_NUM ) return MIOS32_IIC_ERROR_INVALID_PORT; // wait until previous transfer finished if( (error = MIOS32_IIC_TransferWait(iic_port)) ) { // transmission error during previous transfer iicx->iic_semaphore = 0; // release semaphore for easier programming at user level return error + MIOS32_IIC_ERROR_PREV_OFFSET; } // disable interrupts MIOS32_IRQ_Disable(); // TODO: disable peripheral // clear transfer state and error value iicx->transfer_state.ALL = 0; iicx->transfer_error = 0; // set buffer length and start index iicx->buffer_len = len; iicx->buffer_ix = 0; // branch depending on read/write if( transfer == IIC_Read || transfer == IIC_Read_AbortIfFirstByteIs0 ) { // take new address/buffer/len iicx->iic_address = address | 1; // set bit 0 for read operation iicx->tx_buffer_ptr = NULL; // ensure that previous TX buffer won't be accessed iicx->rx_buffer_ptr = buffer; // special option for optimized MBHP_IIC_MIDI iicx->transfer_state.ABORT_IF_FIRST_BYTE_0 = transfer == IIC_Read_AbortIfFirstByteIs0 ? 1 : 0; } else if( transfer == IIC_Write || transfer == IIC_Write_WithoutStop ) { // take new address/buffer/len iicx->iic_address = address & 0xfe; // clear bit 0 for write operation iicx->tx_buffer_ptr = buffer; iicx->rx_buffer_ptr = NULL; // ensure that nothing will be received // option to skip stop-condition generation after successful write iicx->transfer_state.WRITE_WITHOUT_STOP = transfer == IIC_Write_WithoutStop ? 1 : 0; } else { iicx->iic_semaphore = 0; // release semaphore for easier programming at user level MIOS32_IRQ_Enable(); // TODO: enable peripheral?? return (iicx->last_transfer_error=MIOS32_IIC_ERROR_UNSUPPORTED_TRANSFER_TYPE); } // clear last error status iicx->last_transfer_error = 0; // notify that transfer has started iicx->transfer_state.BUSY = 1; MIOS32_IRQ_Enable(); // TODO: enable peripheral // send start condition iicx->base->I2CONCLR = 0x04; // clear AA (assert acknowledge) bit iicx->base->I2CONSET = 0x20; // set STA (start) bit return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // Read a patch ///////////////////////////////////////////////////////////////////////////// s32 MbCvEnvironment::bankLoad(u8 bank, u8 patch, bool forceImmediateChange) { if( bank >= CV_BANK_NUM ) return -2; // invalid bank if( patch >= 128 ) return -3; // invalid patch #if 1 DEBUG_MSG("[CV_BANK_PatchRead] read patch %c%03d\n", 'A'+bank, patch+1); #endif if( mbCvPatch.synchedChange && !forceImmediateChange ) { // request change MIOS32_IRQ_Disable(); mbCvPatch.reqChange = true; mbCvPatch.nextBankNum = bank; mbCvPatch.nextPatchNum = patch; MIOS32_IRQ_Enable(); } else { // do immediate change mbCvPatch.bankNum = bank; mbCvPatch.patchNum = patch; // file operation MBCV_PATCH_Load(bank, patch); #if 0 // update patch structures MbCv *s = mbCv.first(); for(int cv=0; cv < mbCv.size; ++cv, ++s) { s->updatePatch(false); } #endif // send confirmation (e.g. to Lemur) if( lastNrpnMidiPort ) { midiSendNRPNDump(lastNrpnMidiPort, lastNrpnCvChannels, 0); midiSendGlobalNRPNDump(lastNrpnMidiPort); } // change done MIOS32_IRQ_Disable(); mbCvPatch.reqChange = false; mbCvPatch.reqChangeAck = false; MIOS32_IRQ_Enable(); } return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This function should be called from Tick() in main.c // it updates the meters patterns for which an update has been requested ///////////////////////////////////////////////////////////////////////////// s32 LC_METERS_CheckUpdates(void) { u8 meter; u8 meter_select; u8 center_led; u8 level; for(meter=0, meter_select=0x01; meter<8; ++meter) { // check if update has been requested if( meter_update_req & meter_select ) { MIOS32_IRQ_Disable(); meter_update_req &= ~meter_select; // clear request flag MIOS32_IRQ_Enable(); // set LED pattern level = meter_level[meter]; center_led = (level & (1 << 7)) ? 1 : 0; meter_pattern[meter] = meter_patterns[level & 0x0f] | (center_led ? (1 << (12-1)) : 0); } meter_select <<= 1; // shift left the select bit } return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This function should be called from Timer() in main.c every 20 ms (see Init()) // // handles the meter counters. For the best show effect we don't decrement // all meter levels at once every 300 ms, but seperately // // every single counter will be reloaded by lc_mproc.inc::LC_MPROC_Received_D0 // to 15 (== 300 ms / 20 ms), the levels will be decremented when this // value reaches zero ///////////////////////////////////////////////////////////////////////////// s32 LC_METERS_Timer(void) { u8 meter; u8 level; for(meter=0; meter<8; ++meter) { // decrement counter, continue once counter is zero if( !--meter_counter[meter] ) { meter_counter[meter] = 15; // preload counter again // decrement meter level if != 0 level = meter_level[meter]; if( level & 0x7f ) { meter_level[meter] = (level & 0x80) | ((level & 0x7f) - 1); MIOS32_IRQ_Disable(); meter_update_req |= (1 << meter); // request update MIOS32_IRQ_Enable(); LC_LCD_Update_Meter(meter); // request update on LCD } } } return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! puts more than one byte onto the transmit buffer (used for atomic sends) //! \param[in] *buffer pointer to buffer to be sent //! \param[in] len number of bytes to be sent //! \return 0 if no error //! \return -1 if buffer full or cannot get all requested bytes (retry) //! \note Applications shouldn't call these functions directly, instead please use \ref FBV ///////////////////////////////////////////////////////////////////////////// s32 FBV_UART_TxBufferPutMore_NonBlocking( u8 *buffer, u16 len) { if( (tx_buffer_size+len) >= FBV_UART_TX_BUFFER_SIZE ) return -1; // buffer full or cannot get all requested bytes (retry) // copy bytes to be transmitted into transmit buffer // this operation should be atomic! MIOS32_IRQ_Disable(); u16 i; for(i=0; i<len; ++i) { tx_buffer[tx_buffer_head] = *buffer++; if( ++tx_buffer_head >= FBV_UART_TX_BUFFER_SIZE ) tx_buffer_head = 0; // enable Tx interrupt if buffer was empty if( ++tx_buffer_size == 1 ) { FBV_UART->CR1 |= (1 << 7); // enable TXE interrupt (TXEIE=1) } } MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This function sets the meter level ///////////////////////////////////////////////////////////////////////////// s32 LC_METERS_LevelSet(u8 meter, u8 level) { // coding: // meter: channel to be address (0 thru 7) // level: lever meter: // 0 thru C: level meter 0%..100% (overload not cleared!) // E : set overload // F : clear overload // our own coding in METER_LEVEL[meter_number] array: // O000llll // O: overload flag // llll: 1 thru D - lever meter 0%..100% (+1) MIOS32_IRQ_Disable(); if( level == 0x0e ) { // set overload flag // meter_level[meter] |= 0x80; meter_level[meter] = 0x8d; // set overload flag and set level to highest value (seems to be better with Logic Audio) } else if (level == 0x0f ) { // clear overload flag meter_level[meter] &= 0x7f; } else { // set value, dont touch overload flag meter_level[meter] = (meter_level[meter] & 0x80) | ((level & 0x0f) + 1); } meter_update_req |= (1 << meter); // request update of meter LC_LCD_Update_Meter(meter); // request update on LCD MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // resets note stacks used for patch changer ///////////////////////////////////////////////////////////////////////////// s32 SEQ_MIDI_IN_ResetChangerStacks(void) { int i; for(i=0; i<SECTION_CHANGER_NOTESTACK_NUM; ++i) NOTESTACK_Init(§ion_changer_notestack[i], NOTESTACK_MODE_PUSH_TOP, §ion_changer_notestack_items[i][0], SEQ_MIDI_IN_SECTION_CHANGER_NOTESTACK_SIZE); for(i=0; i<PATCH_CHANGER_NOTESTACK_NUM; ++i) NOTESTACK_Init(&patch_changer_notestack[i], NOTESTACK_MODE_PUSH_TOP, &patch_changer_notestack_items[i][0], SEQ_MIDI_IN_PATCH_CHANGER_NOTESTACK_SIZE); // following operation should be atomic! u8 track; seq_core_trk_t *t = &seq_core_trk[0]; MIOS32_IRQ_Disable(); for(track=0; track<SEQ_CORE_NUM_TRACKS; ++track, ++t) t->play_section = 0; // don't select section MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // Access to "SID Available" flags // Each of up to 8 SIDs has a flag - if set to 0, it won't be updated ///////////////////////////////////////////////////////////////////////////// s32 SID_AvailableSet(u8 available) { sid_available = available; #if SID_USE_MBNET MIOS32_IRQ_Disable(); if( sid_available && mbnet_tx_state == MBNET_TX_STATE_NOP ) { // start MBNet transfers once SIDs have been found mbnet_tx_state = MBNET_TX_STATE_SID1; mbnet_tx_reg_ctr = 0; mbnet_tx_msg_ctr = 0; mbnet_tx_msg_ctr_min = 0; mbnet_tx_msg_ctr_max = 0; mbnet_my_node_id = MBNET_NodeIDGet(); MBNET_InstallTxHandler(SID_MBNET_TxHandler); } else if( !sid_available && mbnet_tx_state != MBNET_TX_STATE_NOP ) { // stop MBNet transfers mbnet_tx_state = MBNET_TX_STATE_NOP; MBNET_InstallTxHandler(NULL); } MIOS32_IRQ_Enable(); #endif return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // silence one voice ///////////////////////////////////////////////////////////////////////////// void stopv(struct voicedata*v) { MIOS32_IRQ_Disable(); v->egv[0].state=0; // stop aeg processing for voice v->egv[0].logout=0; v->egv[0].out=0; // silence voice v->egv[1].state=0; // stop feg processing for voice v->egv[1].logout=0; v->egv[1].out=0; v->eg0trip=0; v->o1egstate=1; v->o1eglogout=0; v->o1egout=0; v->o1vol=0; v->o1o=0; v->o1fb=0; v->fk=0; v->chan=NCHAN-1; v->vol=0; v->out=0; v->o0ph=0x00000000; v->o0dph=0x00000000; v->o1dph=0x00000000; v->lo=v->ba=0; MIOS32_IRQ_Enable(); }
///////////////////////////////////////////////////////////////////////////// // Updates all CV channels and gates ///////////////////////////////////////////////////////////////////////////// extern "C" s32 MBCV_MAP_Update(void) { // retrieve the AOUT values of all channels MbCvEnvironment* env = APP_GetEnv(); u16 *out = env->cvOut.first(); for(int cv=0; cv<CV_SE_NUM; ++cv, ++out) AOUT_PinSet(cv, *out); // update AOUTs AOUT_Update(); AOUT_DigitalPinsSet(env->cvGates); // gates and DIN sync signals are available at shift registers u8 gates = AOUT_DigitalPinsGet(); u8 din_sync_value = 0; { if( env->mbCvClock.isRunning ) din_sync_value |= (1 << 0); // START/STOP din_sync_value |= env->mbCvClock.externalClocks << 1; } // following DOUT transfers should be atomic to ensure, that all pins are updated at the same scan cycle MIOS32_IRQ_Disable(); if( mbcv_hwcfg_dout.gate_sr ) MIOS32_DOUT_SRSet(mbcv_hwcfg_dout.gate_sr-1, gates); if( mbcv_hwcfg_dout.clk_sr ) MIOS32_DOUT_SRSet(mbcv_hwcfg_dout.clk_sr-1, din_sync_value); MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This task is running endless in background ///////////////////////////////////////////////////////////////////////////// void APP_Background(void) { // clear LCD screen MIOS32_LCD_Clear(); MIOS32_LCD_CursorSet(0, 0); MIOS32_LCD_PrintString("see README.txt "); MIOS32_LCD_CursorSet(0, 1); MIOS32_LCD_PrintString("for details "); // send delay min/max changes to MIOS terminal while( 1 ) { if( print_message ) { MIOS32_IRQ_Disable(); u32 c_total_delay = total_delay; u32 c_midi_clock_ctr = midi_clock_ctr; delay_t c_d_tick = d_tick; delay_t c_d_beat = d_beat; print_message = 0; MIOS32_IRQ_Enable(); u32 bpm = 60000000 / c_d_beat.delay_last; u32 avg = c_midi_clock_ctr ? (c_total_delay / c_midi_clock_ctr) : 0; MIOS32_MIDI_SendDebugMessage("BPM %d.%d - tick min/avg/max = %d.%03d/%d.%03d/%d.%03d\n", bpm / 1000, bpm % 1000, c_d_tick.delay_min / 1000, c_d_tick.delay_min % 1000, avg / 1000, avg % 1000, c_d_tick.delay_max / 1000, c_d_tick.delay_max % 1000); } } }
///////////////////////////////////////////////////////////////////////////// // This function requests a LEDring update for the given VPots ///////////////////////////////////////////////////////////////////////////// s32 LC_VPOT_LEDRingUpdateSet(u8 rings) { MIOS32_IRQ_Disable(); ledring_update_req |= rings; MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This function sets the meter mode ///////////////////////////////////////////////////////////////////////////// s32 LC_METERS_ModeSet(u8 meter, u8 mode) { meter_mode[meter] = mode; MIOS32_IRQ_Disable(); meter_update_req |= (1 << meter); // request update of meter MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! MSD access functions ///////////////////////////////////////////////////////////////////////////// s32 TASK_MSD_EnableSet(u8 enable) { MIOS32_IRQ_Disable(); if( msd_state == MSD_DISABLED && enable ) { msd_state = MSD_INIT; } else if( msd_state == MSD_READY && !enable ) msd_state = MSD_SHUTDOWN; MIOS32_IRQ_Enable(); return 0; // no error }
s32 SID_Update(u32 mode) { int sid, reg; // if register update should be forced, just inverse all shadow register values if( mode >= 1 ) { // (also for reset mode) MIOS32_IRQ_Disable(); for(sid=0; sid<SID_NUM; ++sid) sid_regs_shadow_updated[sid] = 0xffffffff; MIOS32_IRQ_Enable(); } // transfer SID registers to shadow registers and check for updates MIOS32_IRQ_Disable(); for(sid=0; sid<SID_NUM; ++sid) { u8 *regs = (u8 *)&sid_regs[sid]; u8 *regs_shadow = (u8 *)&sid_regs_shadow[sid]; for(reg=0; reg<SID_REGS_NUM; ++reg) { if( *regs_shadow != *regs ) sid_regs_shadow_updated[sid] |= (1 << reg); *regs_shadow++ = *regs++; } } MIOS32_IRQ_Enable(); // trigger next update if( mbnet_tx_state == MBNET_TX_STATE_DONE && sid_available ) { if( mbnet_tx_msg_ctr && (!mbnet_tx_msg_ctr_min || mbnet_tx_msg_ctr < mbnet_tx_msg_ctr_min) ) mbnet_tx_msg_ctr_min = mbnet_tx_msg_ctr; if( mbnet_tx_msg_ctr > mbnet_tx_msg_ctr_max ) mbnet_tx_msg_ctr_max = mbnet_tx_msg_ctr; mbnet_tx_msg_ctr = 0; mbnet_tx_reg_ctr = 0; mbnet_tx_state = MBNET_TX_STATE_SID1; MBNET_TriggerTxHandler(); } return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // This function sets the absolute vpot value ///////////////////////////////////////////////////////////////////////////// s32 LC_VPOT_ValueSet(u8 vpot, u8 value) { vpot_abs_value[vpot] = value; MIOS32_IRQ_Disable(); ledring_update_req |= (1 << vpot); // request update of ledring MIOS32_IRQ_Enable(); LC_LCD_Update_Knob(vpot); // request update on LCD return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! returns the next byte of the receive buffer without taking it //! \return -1 if no new byte available //! \return >= 0: number of received bytes //! \note Applications shouldn't call these functions directly, instead please use \ref FBV ///////////////////////////////////////////////////////////////////////////// s32 FBV_UART_RxBufferPeek(void) { if( !rx_buffer_size ) return -1; // nothing new in buffer // get byte - this operation should be atomic! MIOS32_IRQ_Disable(); u8 b = rx_buffer[rx_buffer_tail]; MIOS32_IRQ_Enable(); return b; // return received byte }
///////////////////////////////////////////////////////////////////////////// //! puts more than one byte onto the transmit buffer (used for atomic sends) //! \param[in] uart UART number (0..2) //! \param[in] *buffer pointer to buffer to be sent //! \param[in] len number of bytes to be sent //! \return 0 if no error //! \return -1 if UART not available //! \return -2 if buffer full or cannot get all requested bytes (retry) //! \return -3 if UART not supported by MIOS32_UART_TxBufferPut Routine //! \note Applications shouldn't call these functions directly, instead please use \ref MIOS32_COM or \ref MIOS32_MIDI layer functions ///////////////////////////////////////////////////////////////////////////// s32 MIOS32_UART_TxBufferPutMore_NonBlocking(u8 uart, u8 *buffer, u16 len) { #if NUM_SUPPORTED_UARTS == 0 return -1; // no UART available #else if( uart >= NUM_SUPPORTED_UARTS ) return -1; // UART not available if( (tx_buffer_size[uart]+len) >= MIOS32_UART_TX_BUFFER_SIZE ) return -2; // buffer full or cannot get all requested bytes (retry) // copy bytes to be transmitted into transmit buffer // this operation should be atomic! MIOS32_IRQ_Disable(); u16 i; for(i=0; i<len; ++i) { tx_buffer[uart][tx_buffer_head[uart]] = *buffer++; if( ++tx_buffer_head[uart] >= MIOS32_UART_TX_BUFFER_SIZE ) tx_buffer_head[uart] = 0; // enable Tx interrupt if buffer was empty if( ++tx_buffer_size[uart] == 1 ) { switch( uart ) { case 0: MIOS32_UART0->CR1 |= (1 << 7); break; // enable TXE interrupt (TXEIE=1) case 1: MIOS32_UART1->CR1 |= (1 << 7); break; // enable TXE interrupt (TXEIE=1) case 2: MIOS32_UART2_TX->CR1 |= (1 << 7); break; // enable TXE interrupt (TXEIE=1) case 3: MIOS32_UART3->CR1 |= (1 << 7); break; // enable TXE interrupt (TXEIE=1) default: MIOS32_IRQ_Enable(); return -3; // uart not supported by routine (yet) } } } MIOS32_IRQ_Enable(); return 0; // no error #endif }
///////////////////////////////////////////////////////////////////////////// //! gets a byte from the receive buffer //! \return -1 if no new byte available //! \return >= 0: number of received bytes //! \note Applications shouldn't call these functions directly, instead please use \ref FBV ///////////////////////////////////////////////////////////////////////////// s32 FBV_UART_RxBufferGet(void) { if( !rx_buffer_size ) return -1; // nothing new in buffer // get byte - this operation should be atomic! MIOS32_IRQ_Disable(); u8 b = rx_buffer[rx_buffer_tail]; if( ++rx_buffer_tail >= FBV_UART_RX_BUFFER_SIZE ) rx_buffer_tail = 0; --rx_buffer_size; MIOS32_IRQ_Enable(); return b; // return received byte }
///////////////////////////////////////////////////////////////////////////// // This function will be called each second to handle the screen saver ///////////////////////////////////////////////////////////////////////////// s32 SEQ_LCD_LOGO_ScreenSaver_Period1S(void) { // operation should be atomic MIOS32_IRQ_Disable(); if( screen_saver_ctr < (60*(u16)seq_lcd_logo_screensaver_delay) ) { if( ++screen_saver_ctr >= (60*(u16)seq_lcd_logo_screensaver_delay) ) { SEQ_LCD_LOGO_ScreenSaver_Enable(); } } MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // Parser ///////////////////////////////////////////////////////////////////////////// s32 CONSOLE_Parse(mios32_midi_port_t port, u8 byte) { // temporary change debug port (will be restored at the end of this function) mios32_midi_port_t prev_debug_port = MIOS32_MIDI_DebugPortGet(); MIOS32_MIDI_DebugPortSet(port); if( byte == '\r' ) { // ignore } else if( byte == '\n' ) { // example for parsing the command: char *separators = " \t"; char *brkt; char *parameter; if( (parameter = strtok_r(line_buffer, separators, &brkt)) ) { if( strcmp(parameter, "help") == 0 ) { MIOS32_MIDI_SendDebugMessage("Welcome to " MIOS32_LCD_BOOT_MSG_LINE1 "!"); MIOS32_MIDI_SendDebugMessage("Following commands are available:"); MIOS32_MIDI_SendDebugMessage(" reset: clears the current measurements\n"); MIOS32_MIDI_SendDebugMessage(" help: this page\n"); } else if( strcmp(parameter, "reset") == 0 ) { MIOS32_IRQ_Disable(); u8 including_min_max = 1; DelayInit(&d_tick, including_min_max); DelayInit(&d_measure, including_min_max); DelayInit(&d_beat, including_min_max); midi_clock_ctr = 0; total_delay = 0; MIOS32_IRQ_Enable(); MIOS32_MIDI_SendDebugMessage("Measurements have been cleared!\n"); } else { MIOS32_MIDI_SendDebugMessage("Unknown command - type 'help' to list available commands!\n"); } } line_ix = 0; } else if( line_ix < (STRING_MAX-1) ) { line_buffer[line_ix++] = byte; line_buffer[line_ix] = 0; } // restore debug port MIOS32_MIDI_DebugPortSet(prev_debug_port); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! gets a byte from the transmit buffer //! \return -1 if no new byte available //! \return >= 0: transmitted byte //! \note Applications shouldn't call these functions directly, instead please use \ref FBV ///////////////////////////////////////////////////////////////////////////// s32 FBV_UART_TxBufferGet(void) { if( !tx_buffer_size ) return -1; // nothing new in buffer // get byte - this operation should be atomic! MIOS32_IRQ_Disable(); u8 b = tx_buffer[tx_buffer_tail]; if( ++tx_buffer_tail >= FBV_UART_TX_BUFFER_SIZE ) tx_buffer_tail = 0; --tx_buffer_size; MIOS32_IRQ_Enable(); return b; // return transmitted byte }
///////////////////////////////////////////////////////////////////////////// //! puts a byte onto the receive buffer //! \param[in] b byte which should be put into Rx buffer //! \return 0 if no error //! \return -1 if buffer full (retry) //! \note Applications shouldn't call these functions directly, instead please use \ref FBV ///////////////////////////////////////////////////////////////////////////// s32 FBV_UART_RxBufferPut( u8 b) { if( rx_buffer_size >= FBV_UART_RX_BUFFER_SIZE ) return -1; // buffer full (retry) // copy received byte into receive buffer // this operation should be atomic! MIOS32_IRQ_Disable(); rx_buffer[rx_buffer_head] = b; if( ++rx_buffer_head >= FBV_UART_RX_BUFFER_SIZE ) rx_buffer_head = 0; ++rx_buffer_size; MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// // called whenever record variables should be reseted (e.g. on track restart) ///////////////////////////////////////////////////////////////////////////// s32 SEQ_RECORD_Reset(u8 track) { // exit if track number too high if( track >= SEQ_CORE_NUM_TRACKS ) return -1; // unsupported track seq_core_trk_t *t = &seq_core_trk[track]; // init track specific variables MIOS32_IRQ_Disable(); t->state.REC_DONT_OVERWRITE_NEXT_STEP = 0; t->rec_timestamp = 0; t->rec_poly_ctr = 0; MIOS32_IRQ_Enable(); return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! Returns the DIN pin toggle notifications after a SRIO scan. Should be used //! to check and clear these flags when processed by a DIN handler for exclusive //! access (avoid propagation of already handled DIN pin changes) //! //! Examples:<BR> //! 1) if a scan matrix handler processes the DIN pins of the first SR, //! it should call //! \code //! changed = MIOS32_DIN_SRChangedGetAndClear(0, 0xff) //! \endcode //! to get a notification, if (and which) pins have toggled during the last scan. //! The flags will be cleared, so that the remaining handlers won't process //! the pins of the first DIN register anymore. //! //! 2) it's also possible, to check and clear only dedicated pins of the DIN //! register by applying a different pin mask. E.g. //! \code //! changed = MIOS32_DIN_SRChangedGetAndClear(0, 0xc0) //! \endcode //! will only check/clear D6 and D7 of the DIN register, the remaining //! toggle notifications won't be touched and will be forwarded to remaining //! handlers //! \param[in] sr shift register number (0..15) //! \param[in] mask pin mask (8bit value) //! \return 8bit value which contains the selected (masked) change flags //! \return no error status (-1)! - if unavailable SR selected, 0x00 will be returned ///////////////////////////////////////////////////////////////////////////// u8 MIOS32_DIN_SRChangedGetAndClear(u32 sr, u8 mask) { u8 num_sr = MIOS32_SRIO_ScanNumGet(); u8 changed; // check if SR available if( sr >= num_sr ) return 0x00; // get and clear changed flags - must be atomic! MIOS32_IRQ_Disable(); changed = mios32_srio_din_changed[sr] & mask; mios32_srio_din_changed[sr] &= ~mask; MIOS32_IRQ_Enable(); return changed; }
///////////////////////////////////////////////////////////////////////////// // For Section Changes // If velocity == 0, Note Off event has been received, otherwise Note On event ///////////////////////////////////////////////////////////////////////////// static s32 SEQ_MIDI_IN_Receive_NoteSC(u8 note, u8 velocity) { int octave = note / 12; int octave_taken = 0; int group; for(group=0; group<4; ++group) { if( octave == (seq_midi_in_sect_note[group] / 12) ) { octave_taken = 1; notestack_t *n = §ion_changer_notestack[group]; int section = -1; if( velocity ) { // Note On NOTESTACK_Push(n, note, velocity); section = n->note_items[0].note % 12; } else { // Note Off if( NOTESTACK_Pop(n, note) > 0 && n->len ) { section = n->note_items[0].note % 12; } } // switch to new section if required if( section >= 0 && section < 12 ) { #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("Group %d Section %d\n", group, section); #endif // following operation should be atomic! u8 track; seq_core_trk_t *t = &seq_core_trk[group*SEQ_CORE_NUM_TRACKS_PER_GROUP]; MIOS32_IRQ_Disable(); for(track=0; track<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++track, ++t) t->play_section = section; MIOS32_IRQ_Enable(); } #if DEBUG_VERBOSE_LEVEL >= 1 DEBUG_MSG("NOTESTACK_SECTION_CHANGER_G%d:\n", group+1); NOTESTACK_SendDebugMessage(n); #endif } } return octave_taken; // return 1 if octave has been taken, otherwise 0 }
///////////////////////////////////////////////////////////////////////////// //! This function should be called from a task to check for button changes //! periodically. Events (change from 0->1 or from 1->0) will be notified //! via the given callback function <notify_hook> with following parameters: //! <notifcation-hook>(s32 pin, s32 value) //! \return < 0 on errors ///////////////////////////////////////////////////////////////////////////// s32 BLM_CHEAPO_ButtonHandler(void *_notify_hook) { void (*notify_hook)(u32 pin, u32 value) = _notify_hook; // no hook? if( _notify_hook == NULL ) return -2; int row; for(row=0; row<NUM_ROWS; ++row) { // check if there are pin changes - must be atomic! MIOS32_IRQ_Disable(); u8 changed = button_row_changed[row]; button_row_changed[row] = 0; MIOS32_IRQ_Enable(); // any pin change at this SR? if( !changed ) continue; // check all 8 pins of the SR int pin; u8 mask = (1 << 0); for(pin=0; pin<8; ++pin, mask <<= 1) if( changed & mask ) { u8 pin_value = (button_row[row] & (1 << pin)) ? 1 : 0; #if BLM_CHEAPO_RIGHT_HALF_REVERSED // reverse pins for right half (layout measure) u8 blm_pin = pin; if( row >= 4 ) { blm_pin = 7 - pin; } #endif #if 0 MIOS32_MIDI_SendDebugMessage("[BLM_CHEAPO] Row:%d Pin:%d Value:%d\n", row, blm_pin, pin_value); #endif notify_hook(8*row + blm_pin, pin_value); } } return 0; // no error }
///////////////////////////////////////////////////////////////////////////// //! Updates the output channels of all DPOT channels //! Should be called, whenever changes have been requested via //! DPOT_Set_Value() //! \return < 0 on errors ///////////////////////////////////////////////////////////////////////////// s32 DPOT_Update(void) { s32 status = 0; u32 req = 0; // check for DPOT channel update requests MIOS32_IRQ_Disable(); req = dpot_update_req; dpot_update_req = 0; MIOS32_IRQ_Enable(); // update hardware if (req) { status = DPOT_Device_Update(req); } return status; }
///////////////////////////////////////////////////////////////////////////// //! returns the next byte of the receive buffer without taking it //! \param[in] uart UART number (0..2) //! \return -1 if UART not available //! \return -2 if no new byte available //! \return >= 0: number of received bytes //! \note Applications shouldn't call these functions directly, instead please use \ref MIOS32_COM or \ref MIOS32_MIDI layer functions ///////////////////////////////////////////////////////////////////////////// s32 MIOS32_UART_RxBufferPeek(u8 uart) { #if MIOS32_UART_NUM == 0 return -1; // no UART available #else if( uart >= MIOS32_UART_NUM ) return -1; // UART not available if( !rx_buffer_size[uart] ) return -2; // nothing new in buffer // get byte - this operation should be atomic! MIOS32_IRQ_Disable(); u8 b = rx_buffer[uart][rx_buffer_tail[uart]]; MIOS32_IRQ_Enable(); return b; // return received byte #endif }
///////////////////////////////////////////////////////////////////////////// // This function should be called from Tick() in main.c // it updates the LEDring patterns for which an update has been requested ///////////////////////////////////////////////////////////////////////////// s32 LC_VPOT_LEDRing_CheckUpdates(void) { u8 ledring; u8 ledring_select; u8 value; u8 center_led; for(ledring=0, ledring_select=0x01; ledring<8; ++ledring) { // check if update has been requested if( ledring_update_req & ledring_select ) { MIOS32_IRQ_Disable(); ledring_update_req &= ~ledring_select; // clear request flag MIOS32_IRQ_Enable(); // branch depending on mode if( lc_flags.GPC_SEL ) { value = LC_GPC_VPotValueGet(ledring); ledring_pattern[ledring] = preset_patterns_gpc[value >> 2]; } else {