static void print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg) { const char *einfo = ""; long elen = 0; VALUE mesg; if (emesg != Qundef) { if (NIL_P(errat) || RARRAY_LEN(errat) == 0 || NIL_P(mesg = RARRAY_AREF(errat, 0))) { error_pos(); } else { warn_print_str(mesg); warn_print(": "); } if (!NIL_P(emesg)) { einfo = RSTRING_PTR(emesg); elen = RSTRING_LEN(emesg); } } if (eclass == rb_eRuntimeError && elen == 0) { warn_print("unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print_str(epath); warn_print("\n"); } else { const char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print_str(tail ? rb_str_subseq(emesg, 0, len) : emesg); if (epath) { warn_print(" ("); warn_print_str(epath); warn_print(")\n"); } if (tail) { warn_print_str(rb_str_subseq(emesg, tail - einfo, elen - len - 1)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } }
// Sends a System Control code to the USB Output buffer void Output_sysCtrlSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_sysCtrlSend(sysCode)"); return; } // Not implemented in Boot Mode if ( USBKeys_Protocol == 0 ) { warn_print("System Control is not implemented for Boot Mode"); return; } // TODO Analog inputs // Only indicate USB has changed if either a press or release has occured if ( state == 0x01 || state == 0x03 ) USBKeys_Changed |= USBKeyChangeState_System; // Only send keypresses if press or hold state if ( stateType == 0x00 && state == 0x03 ) // Release state { USBKeys_SysCtrl = 0; return; } // Set system control code USBKeys_SysCtrl = args[0]; }
// Setup inline void Port_setup() { // Register Scan CLI dictionary CLI_registerDictionary( portCLIDict, portCLIDictName ); #if Port_SwapMode_define == USBSwap // USB Swap // Start, disabled GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); #elif Port_SwapMode_define == USBInterSwap // USB Swap // Start, disabled GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); // UART Tx/Rx cross-over // Start, disabled GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); // UART Swap // Start, disabled GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveSetup, GPIO_Config_None ); GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveLow, GPIO_Config_None ); #else warn_print("Unsupported"); #endif // Starting point for automatic port swapping Port_lastcheck_ms = systick_millis_count; // Allocate latency measurement resource portLatencyResource = Latency_add_resource("PortSwap", LatencyOption_Ticks); }
void Port_uart_swap() { #if Port_SwapMode_define == USBInterSwap info_print("Interconnect Line Swap"); // UART Swap GPIO_Ctrl( uart_swap_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); #else warn_print("Unsupported"); #endif }
/* rb_warning() reports only in verbose mode */ void rb_warning(const char *fmt, ...) { va_list args; if (!RTEST(ruby_verbose)) return; va_start(args, fmt); warn_print(fmt, args); va_end(args); }
/* rb_warning() reports only in verbose mode */ void rb_warning(const char *fmt, ...) { char buf[BUFSIZ]; va_list args; if (!RTEST(ruby_verbose)) return; snprintf(buf, BUFSIZ, "warning: %s", fmt); va_start(args, fmt); warn_print(buf, args); va_end(args); }
void Port_cross() { #if Port_SwapMode_define == USBInterSwap info_print("Interconnect Line Cross"); // UART Tx/Rx cross-over GPIO_Ctrl( uart_cross_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); // Reset interconnects Connect_reset(); #else warn_print("Unsupported"); #endif }
void Port_usb_swap() { #if Port_SwapMode_define == USBSwap || Port_SwapMode_define == USBInterSwap info_print("USB Port Swap"); // USB Swap GPIO_Ctrl( usb_swap_pin1, GPIO_Type_DriveToggle, GPIO_Config_None ); // Re-initialize usb // Call usb_configured() to check if usb is ready usb_reinit(); #else warn_print("Unsupported"); #endif }
void rb_sys_warning(const char *fmt, ...) { char buf[BUFSIZ]; va_list args; int errno_save; errno_save = errno; if (!RTEST(ruby_verbose)) return; snprintf(buf, BUFSIZ, "warning: %s", fmt); snprintf(buf+strlen(buf), BUFSIZ-strlen(buf), ": %s", strerror(errno_save)); va_start(args, fmt); warn_print(buf, args); va_end(args); errno = errno_save; }
void rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) { volatile VALUE errat = Qundef; volatile int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, emesg = Qundef; if (NIL_P(errinfo)) return; rb_thread_raised_clear(th); TH_PUSH_TAG(th); if (TH_EXEC_TAG() == 0) { errat = rb_get_backtrace(errinfo); } else if (errat == Qundef) { errat = Qnil; } else if (eclass == Qundef || emesg != Qundef) { goto error; } if ((eclass = CLASS_OF(errinfo)) != Qundef) { VALUE e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0); if (e != Qundef) { if (!RB_TYPE_P(e, T_STRING)) e = rb_check_string_type(e); emesg = e; } } if (rb_stderr_tty_p()) { if (0) warn_print("Traceback (most recent call last):\n"); print_backtrace(eclass, errat, TRUE); print_errinfo(eclass, errat, emesg); } else { print_errinfo(eclass, errat, emesg); print_backtrace(eclass, errat, FALSE); } error: TH_POP_TAG(); th->errinfo = errinfo; rb_thread_raised_set(th, raised_flag); }
uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num ) { // Check if this is the first byte if ( *pending_bytes == 0xFFFF ) { *pending_bytes = byte; if ( Connect_debug ) { dbug_msg("PENDING SET -> "); printHex( byte ); print(" "); printHex( *pending_bytes ); print( NL ); } } // Verify byte else { (*pending_bytes)--; // The argument bytes are always 0xD2 (11010010) if ( byte != 0xD2 ) { warn_print("Cable Fault!"); // Check which side of the chain if ( uart_num == UART_Slave ) { Connect_cableFaultsSlave++; Connect_cableOkSlave = 0; print(" Slave "); } else { Connect_cableFaultsMaster++; Connect_cableOkMaster = 0; print(" Master "); } printHex( byte ); print( NL ); // Signal that the command should wait for a SYN again return 1; } else { // Check which side of the chain if ( uart_num == UART_Slave ) { Connect_cableChecksSlave++; } else { Connect_cableChecksMaster++; } } } // If cable check was successful, set cable ok if ( *pending_bytes == 0 ) { if ( uart_num == UART_Slave ) { Connect_cableOkSlave = 1; } else { Connect_cableOkMaster = 1; } } if ( Connect_debug ) { dbug_msg("CABLECHECK RECEIVE - "); printHex( byte ); print(" "); printHex( *pending_bytes ); print( NL ); } // Check whether the cable check has finished return *pending_bytes == 0 ? 1 : 0; }
// send the contents of keyboard_keys and keyboard_modifier_keys void usb_keyboard_send() { uint32_t wait_count = 0; usb_packet_t *tx_packet; // Wait till ready while ( 1 ) { if ( !usb_configuration ) { erro_print("USB not configured..."); return; } if ( USBKeys_Protocol == 0 ) // Boot Mode { if ( usb_tx_packet_count( NKRO_KEYBOARD_ENDPOINT ) < TX_PACKET_LIMIT ) { tx_packet = usb_malloc(); if ( tx_packet ) break; } } else if ( USBKeys_Protocol == 1 ) // NKRO Mode { if ( usb_tx_packet_count( KEYBOARD_ENDPOINT ) < TX_PACKET_LIMIT ) { tx_packet = usb_malloc(); if ( tx_packet ) break; } } if ( ++wait_count > TX_TIMEOUT || transmit_previous_timeout ) { transmit_previous_timeout = 1; warn_print("USB Transmit Timeout..."); return; } yield(); } // Pointer to USB tx packet buffer uint8_t *tx_buf = tx_packet->buf; switch ( USBKeys_Protocol ) { // Send boot keyboard interrupt packet(s) case 0: // USB Boot Mode debug output if ( Output_DebugMode ) { dbug_msg("Boot USB: "); printHex_op( USBKeys_Modifiers, 2 ); print(" "); printHex( 0 ); print(" "); printHex_op( USBKeys_Keys[0], 2 ); printHex_op( USBKeys_Keys[1], 2 ); printHex_op( USBKeys_Keys[2], 2 ); printHex_op( USBKeys_Keys[3], 2 ); printHex_op( USBKeys_Keys[4], 2 ); printHex_op( USBKeys_Keys[5], 2 ); print( NL ); } // Boot Mode *tx_buf++ = USBKeys_Modifiers; *tx_buf++ = 0; memcpy( tx_buf, USBKeys_Keys, USB_BOOT_MAX_KEYS ); tx_packet->len = 8; // Send USB Packet usb_tx( KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed = USBKeyChangeState_None; break; // Send NKRO keyboard interrupts packet(s) case 1: if ( Output_DebugMode ) { dbug_msg("NKRO USB: "); } // Check system control keys if ( USBKeys_Changed & USBKeyChangeState_System ) { if ( Output_DebugMode ) { print("SysCtrl["); printHex_op( USBKeys_SysCtrl, 2 ); print( "] " NL ); } *tx_buf++ = 0x02; // ID *tx_buf = USBKeys_SysCtrl; tx_packet->len = 2; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed &= ~USBKeyChangeState_System; // Mark sent } // Check consumer control keys if ( USBKeys_Changed & USBKeyChangeState_Consumer ) { if ( Output_DebugMode ) { print("ConsCtrl["); printHex_op( USBKeys_ConsCtrl, 2 ); print( "] " NL ); } *tx_buf++ = 0x03; // ID *tx_buf++ = (uint8_t)(USBKeys_ConsCtrl & 0x00FF); *tx_buf = (uint8_t)(USBKeys_ConsCtrl >> 8); tx_packet->len = 3; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed &= ~USBKeyChangeState_Consumer; // Mark sent } // Standard HID Keyboard if ( USBKeys_Changed ) { // USB NKRO Debug output if ( Output_DebugMode ) { printHex_op( USBKeys_Modifiers, 2 ); print(" "); for ( uint8_t c = 0; c < 6; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print(" "); for ( uint8_t c = 6; c < 20; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print(" "); printHex_op( USBKeys_Keys[20], 2 ); print(" "); for ( uint8_t c = 21; c < 27; c++ ) printHex_op( USBKeys_Keys[ c ], 2 ); print( NL ); } tx_packet->len = 0; // Modifiers *tx_buf++ = 0x01; // ID *tx_buf++ = USBKeys_Modifiers; tx_packet->len += 2; // 4-49 (first 6 bytes) memcpy( tx_buf, USBKeys_Keys, 6 ); tx_buf += 6; tx_packet->len += 6; // 51-155 (Middle 14 bytes) memcpy( tx_buf, USBKeys_Keys + 6, 14 ); tx_buf += 14; tx_packet->len += 14; // 157-164 (Next byte) memcpy( tx_buf, USBKeys_Keys + 20, 1 ); tx_buf += 1; tx_packet->len += 1; // 176-221 (last 6 bytes) memcpy( tx_buf, USBKeys_Keys + 21, 6 ); tx_packet->len += 6; // Send USB Packet usb_tx( NKRO_KEYBOARD_ENDPOINT, tx_packet ); USBKeys_Changed = USBKeyChangeState_None; // Mark sent } break; } return; }
// Adds a single USB Code to the USB Output buffer // Argument #1: USB Code void Output_usbCodeSend_capability( TriggerMacro *trigger, uint8_t state, uint8_t stateType, uint8_t *args ) { #if enableKeyboard_define == 1 // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_usbCodeSend(usbCode)"); return; } // Depending on which mode the keyboard is in the USB needs Press/Hold/Release events uint8_t keyPress = 0; // Default to key release // Only send press and release events if ( stateType == 0x00 && state == 0x02 ) // Hold state return; // If press, send bit (NKRO) or byte (6KRO) if ( stateType == 0x00 && state == 0x01 ) // Press state keyPress = 1; // Get the keycode from arguments uint8_t key = args[0]; // Depending on which mode the keyboard is in, USBKeys_Keys array is used differently // Boot mode - Maximum of 6 byte codes // NKRO mode - Each bit of the 26 byte corresponds to a key // Bits 0 - 45 (bytes 0 - 5) correspond to USB Codes 4 - 49 (Main) // Bits 48 - 161 (bytes 6 - 20) correspond to USB Codes 51 - 164 (Secondary) // Bits 168 - 213 (bytes 21 - 26) correspond to USB Codes 176 - 221 (Tertiary) // Bits 214 - 216 unused uint8_t bytePosition = 0; uint8_t byteShift = 0; switch ( USBKeys_Protocol ) { case 0: // Boot Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_primary.modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_primary.modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_primary.changed |= USBKeyChangeState_Modifiers; } // Normal USB Code else { // Determine if key was set uint8_t keyFound = 0; uint8_t old_sent = USBKeys_Sent; for ( uint8_t curkey = 0, newkey = 0; curkey < old_sent; curkey++, newkey++ ) { // On press, key already present, don't re-add if ( keyPress && USBKeys_primary.keys[newkey] == key ) { keyFound = 1; break; } // On release, remove if found if ( !keyPress && USBKeys_primary.keys[newkey] == key ) { // Shift next key onto this one // (Doesn't matter if it overflows, buffer is large enough, and size is used) USBKeys_primary.keys[newkey--] = USBKeys_primary.keys[++curkey]; USBKeys_Sent--; keyFound = 1; USBKeys_primary.changed = USBKeyChangeState_MainKeys; break; } } // USB Key limit reached if ( USBKeys_Sent >= USB_BOOT_MAX_KEYS ) { warn_print("USB Key limit reached"); break; } // Add key if not already found in the buffer if ( keyPress && !keyFound ) { USBKeys_primary.keys[USBKeys_Sent++] = key; USBKeys_primary.changed = USBKeyChangeState_MainKeys; } } break; case 1: // NKRO Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_primary.modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_primary.modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_primary.changed |= USBKeyChangeState_Modifiers; break; } // First 6 bytes else if ( key >= 4 && key <= 49 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 0th position, each byte has 8 bits, starting at 4th bit uint8_t keyPos = key + (0 * 8 - 4); // Starting position in array, Ignoring 4 keys switch ( keyPos ) { byteLookup( 0 ); byteLookup( 1 ); byteLookup( 2 ); byteLookup( 3 ); byteLookup( 4 ); byteLookup( 5 ); } USBKeys_primary.changed |= USBKeyChangeState_MainKeys; } // Next 14 bytes else if ( key >= 51 && key <= 155 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 6th byte position, each byte has 8 bits, starting at 51st bit uint8_t keyPos = key + (6 * 8 - 51); // Starting position in array switch ( keyPos ) { byteLookup( 6 ); byteLookup( 7 ); byteLookup( 8 ); byteLookup( 9 ); byteLookup( 10 ); byteLookup( 11 ); byteLookup( 12 ); byteLookup( 13 ); byteLookup( 14 ); byteLookup( 15 ); byteLookup( 16 ); byteLookup( 17 ); byteLookup( 18 ); byteLookup( 19 ); } USBKeys_primary.changed |= USBKeyChangeState_SecondaryKeys; } // Next byte else if ( key >= 157 && key <= 164 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (20 * 8 - 157); // Starting position in array, Ignoring 6 keys switch ( keyPos ) { byteLookup( 20 ); } USBKeys_primary.changed |= USBKeyChangeState_TertiaryKeys; } // Last 6 bytes else if ( key >= 176 && key <= 221 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (21 * 8 - 176); // Starting position in array switch ( keyPos ) { byteLookup( 21 ); byteLookup( 22 ); byteLookup( 23 ); byteLookup( 24 ); byteLookup( 25 ); byteLookup( 26 ); } USBKeys_primary.changed |= USBKeyChangeState_QuartiaryKeys; } // Received 0x00 // This is a special USB Code that internally indicates a "break" // It is used to send "nothing" in order to break up sequences of USB Codes else if ( key == 0x00 ) { USBKeys_primary.changed |= USBKeyChangeState_MainKeys; // Also flush out buffers just in case Output_flushBuffers(); break; } // Invalid key else { warn_msg("USB Code not within 4-49 (0x4-0x31), 51-155 (0x33-0x9B), 157-164 (0x9D-0xA4), 176-221 (0xB0-0xDD) or 224-231 (0xE0-0xE7) NKRO Mode: "); printHex( key ); print( NL ); break; } // Set/Unset if ( keyPress ) { USBKeys_primary.keys[bytePosition] |= (1 << byteShift); USBKeys_Sent--; } else // Release { USBKeys_primary.keys[bytePosition] &= ~(1 << byteShift); USBKeys_Sent++; } break; } #endif }
uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num ) { // Check if this is the first byte if ( *pending_bytes == BYTE_COUNT_START ) { *pending_bytes = byte; if ( Connect_debug ) { dbug_msg("PENDING SET -> "); printHex( byte ); print(" "); printHex( *pending_bytes ); print( NL ); } } // Verify byte else { (*pending_bytes)--; // The argument bytes are always 0xD2 (11010010) if ( byte != CABLE_CHECK_ARG ) { warn_print("Cable Fault!"); // Check which side of the chain if ( uart_num == UART_Slave ) { Connect_cableFaultsSlave++; Connect_cableOkSlave = 0; print(" Slave "); } else { // Lower current requirement during errors // Half of USB negotiation minimum (50 mA) // Only if this is not the master node if ( Connect_id != 0 ) { Output_update_external_current( 50 ); } Connect_cableFaultsMaster++; Connect_cableOkMaster = 0; print(" Master "); } printHex( byte ); print( NL ); // Signal that the command should wait for a SYN again return 1; } else { // Check which side of the chain if ( uart_num == UART_Slave ) { Connect_cableChecksSlave++; } else { // If we already have an Id, then set max current again if ( Connect_id != 255 && Connect_id != 0 ) { Output_update_external_current( Output_current_available() ); } Connect_cableChecksMaster++; } } } // If cable check was successful, set cable ok if ( *pending_bytes == 0 ) { if ( uart_num == UART_Slave ) { Connect_cableOkSlave = 1; } else { Connect_cableOkMaster = 1; } } if ( Connect_debug ) { dbug_msg("CABLECHECK RECEIVE - "); printHex( byte ); print(" "); printHex( *pending_bytes ); print( NL ); } // Check whether the cable check has finished return *pending_bytes == 0 ? 1 : 0; }
void i2c_isr( uint8_t ch ) { volatile I2C_Channel* channel = &i2c_channels[ch - ISSI_I2C_FirstBus_define]; #if defined(_kinetis_) volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; volatile uint8_t *I2C_S = (uint8_t*)(&I2C0_S) + i2c_offset[ch]; volatile uint8_t *I2C_D = (uint8_t*)(&I2C0_D) + i2c_offset[ch]; #elif defined(_sam_) Twi *twi_dev = twi_devs[ch]; #endif uint16_t element; uint8_t status; #if defined(_kinetis_) status = *I2C_S; // Acknowledge the interrupt request *I2C_S |= I2C_S_IICIF; // Arbitration problem if ( status & I2C_S_ARBL ) { /* XXX (HaaTa) I2C Debugging warn_msg("Arbitration error. Bus: "); printHex( ch ); print(NL); */ *I2C_S |= I2C_S_ARBL; goto i2c_isr_error; } #elif defined(_sam_) status = twi_dev->TWI_SR; // Arbitration problem if ( status & TWI_SR_ARBLST ) { warn_msg("Arbitration error. Bus: "); printHex( ch ); print(NL); goto i2c_isr_error; } #endif if ( channel->txrx == I2C_READING ) { switch( channel->reads_ahead ) { // All the reads in the sequence have been processed ( but note that the final data register read still needs to // be done below! Now, the next thing is either a restart or the end of a sequence. case 0: #if defined(_kinetis_) // In any case, we need to switch to TX mode, either to generate a repeated start condition, or to avoid // triggering another I2C read when reading the contents of the data register. *I2C_C1 |= I2C_C1_TX; // Perform the final data register read now that it's safe to do so. *channel->received_data++ = *I2C_D; // Do we have a repeated start? if ( ( channel->sequence < channel->sequence_end ) && ( *channel->sequence == I2C_RESTART ) ) { // Generate a repeated start condition. *I2C_C1 |= I2C_C1_RSTA; // A restart is processed immediately, so we need to get a new element from our sequence. This is safe, because // a sequence cannot end with a RESTART: there has to be something after it. Note that the only thing that can // come after a restart is an address write. channel->txrx = I2C_WRITING; channel->sequence++; element = *channel->sequence; *I2C_D = element; } else { goto i2c_isr_stop; } #elif defined(_sam_) // Perform the final data register read now that it's safe to do so. *channel->received_data++ = twi_dev->TWI_RHR; // Do we have a repeated start? if ( ( channel->sequence < channel->sequence_end ) && ( *channel->sequence == I2C_RESTART ) ) { // Generate a repeated start condition. twi_dev->TWI_MMR &= ~TWI_MMR_MREAD; twi_dev->TWI_CR |= TWI_CR_START; // A restart is processed immediately, so we need to get a new element from our sequence. This is safe, because // a sequence cannot end with a RESTART: there has to be something after it. Note that the only thing that can // come after a restart is an address write. channel->txrx = I2C_WRITING; channel->sequence++; element = *channel->sequence; twi_dev->TWI_THR = element; } else { goto i2c_isr_stop; } #endif break; case 1: #if defined(_kinetis_) // do not ACK the final read *I2C_C1 |= I2C_C1_TXAK; *channel->received_data++ = *I2C_D; #elif defined(_sam_) twi_dev->TWI_CR |= TWI_CR_STOP; //No ACK *channel->received_data++ = twi_dev->TWI_RHR; #endif break; default: #if defined(_kinetis_) *channel->received_data++ = *I2C_D; #elif defined(_sam_) *channel->received_data++ = twi_dev->TWI_RHR; #endif break; } //print("Read: "); //printHex( *channel->received_data ); //print( NL ); channel->reads_ahead--; } // channel->txrx == I2C_WRITING else { // First, check if we are at the end of a sequence. if ( channel->sequence == channel->sequence_end ) goto i2c_isr_stop; // We received a NACK. Generate a STOP condition and abort. #if defined(_kinetis_) if ( status & I2C_S_RXAK ) { warn_print("NACK Received"); goto i2c_isr_error; } #elif defined(_sam_) if ( status & TWI_SR_NACK ) { warn_print("NACK Received"); goto i2c_isr_error; } #endif // check next thing in our sequence element = *channel->sequence; // Do we have a restart? If so, generate repeated start and make sure TX is on. if ( element == I2C_RESTART ) { #if defined(_kinetis_) *I2C_C1 |= I2C_C1_RSTA | I2C_C1_TX; #elif defined(_sam_) twi_dev->TWI_MMR &= ~TWI_MMR_MREAD; twi_dev->TWI_CR |= TWI_CR_START; #endif // A restart is processed immediately, so we need to get a new element from our sequence. // This is safe, because a sequence cannot end with a RESTART: there has to be something after it. channel->sequence++; element = *channel->sequence; // Note that the only thing that can come after a restart is a write. #if defined(_kinetis_) *I2C_D = element; #elif defined(_sam_) twi_dev->TWI_THR = element; #endif } else { if ( element == I2C_READ ) { channel->txrx = I2C_READING; // How many reads do we have ahead of us ( not including this one )? // For reads we need to know the segment length to correctly plan NACK transmissions. // We already know about one read channel->reads_ahead = 1; while ( ( ( channel->sequence + channel->reads_ahead ) < channel->sequence_end ) && ( *( channel->sequence + channel->reads_ahead ) == I2C_READ ) ) { channel->reads_ahead++; } // Switch to RX mode. #if defined(_kinetis_) *I2C_C1 &= ~I2C_C1_TX; #elif defined(_sam_) twi_dev->TWI_MMR |= TWI_MMR_MREAD; #endif // do not ACK the final read if ( channel->reads_ahead == 1 ) { #if defined(_kinetis_) *I2C_C1 |= I2C_C1_TXAK; #elif defined(_sam_) twi_dev->TWI_CR |= TWI_CR_STOP; #endif } // ACK all but the final read else { #if defined(_kinetis_) *I2C_C1 &= ~( I2C_C1_TXAK ); #endif } // Dummy read comes first, note that this is not valid data! // This only triggers a read, actual data will come in the next interrupt call and overwrite this. // This is why we do not increment the received_data pointer. #if defined(_kinetis_) *channel->received_data = *I2C_D; #elif defined(_sam_) *channel->received_data = twi_dev->TWI_RHR; #endif channel->reads_ahead--; } // Not a restart, not a read, must be a write. else { //print("WRITE: "); //printHex(element); #if defined(_kinetis_) *I2C_D = element; #elif defined(_sam_) // while (! (status & TWI_SR_TXRDY)); if (!(status & TWI_SR_TXRDY)) return; twi_dev->TWI_THR = element; #endif //print( NL ); } } } channel->sequence++; channel->last_error = 0; // No error return; i2c_isr_stop: // Generate STOP ( set MST=0 ), switch to RX mode, and disable further interrupts. #if defined(_kinetis_) *I2C_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE | I2C_C1_TXAK ); #elif defined(_sam_) //print("\r\n ----- STOP ----- \r\n"); twi_dev->TWI_CR |= TWI_CR_STOP; twi_dev->TWI_MMR &= ~TWI_MMR_MREAD; twi_dev->TWI_IDR = 0xFFFFFFFF; #endif channel->status = I2C_AVAILABLE; // Call the user-supplied callback function upon successful completion (if it exists). if ( channel->callback_fn ) { // Delay before starting linked function #if ISSI_Chip_31FL3731_define == 1 || ISSI_Chip_31FL3732_define == 1 delay_us(25); #elif ISSI_Chip_31FL3733_define == 1 || ISSI_Chip_31FL3736_define == 1 delay_us(10); #endif ( *channel->callback_fn )( channel->user_data ); } return; i2c_isr_error: // Record error, and reset last error counter channel->error_count++; channel->last_error++; // Generate STOP and disable further interrupts. warn_print("ISR error"); #if defined(_kinetis_) *I2C_C1 &= ~( I2C_C1_MST | I2C_C1_IICIE ); #elif defined(_sam_) twi_dev->TWI_CR |= TWI_CR_STOP; twi_dev->TWI_IDR = 0xFFFFFFFF; #endif channel->status = I2C_ERROR; return; }
static int error_handle(int ex) { int status = EXIT_FAILURE; rb_thread_t *th = GET_THREAD(); if (rb_threadptr_set_raised(th)) return EXIT_FAILURE; switch (ex & TAG_MASK) { case 0: status = EXIT_SUCCESS; break; case TAG_RETURN: error_pos(); warn_print("unexpected return\n"); break; case TAG_NEXT: error_pos(); warn_print("unexpected next\n"); break; case TAG_BREAK: error_pos(); warn_print("unexpected break\n"); break; case TAG_REDO: error_pos(); warn_print("unexpected redo\n"); break; case TAG_RETRY: error_pos(); warn_print("retry outside of rescue clause\n"); break; case TAG_THROW: /* TODO: fix me */ error_pos(); warn_print("unexpected throw\n"); break; case TAG_RAISE: { VALUE errinfo = th->errinfo; if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) { status = sysexit_status(errinfo); } else if (rb_obj_is_instance_of(errinfo, rb_eSignal) && rb_ivar_get(errinfo, id_signo) != INT2FIX(SIGSEGV)) { /* no message when exiting by signal */ } else { error_print(th); } break; } case TAG_FATAL: error_print(th); break; default: unknown_longjmp_status(ex); break; } rb_threadptr_reset_raised(th); return status; }
static void error_print(void) { volatile VALUE errat = Qnil; /* OK */ VALUE errinfo = GET_THREAD()->errinfo; volatile VALUE eclass, e; const char *volatile einfo; volatile long elen; if (NIL_P(errinfo)) return; PUSH_TAG(); if (EXEC_TAG() == 0) { errat = get_backtrace(errinfo); } else { errat = Qnil; } if (EXEC_TAG()) goto error; if (NIL_P(errat)) { const char *file = rb_sourcefile(); int line = rb_sourceline(); if (!file) warn_printf("%d", line); else if (!line) warn_printf("%s", file); else warn_printf("%s:%d", file, line); } else if (RARRAY_LEN(errat) == 0) { error_pos(); } else { VALUE mesg = RARRAY_PTR(errat)[0]; if (NIL_P(mesg)) error_pos(); else { warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg)); } } eclass = CLASS_OF(errinfo); if (EXEC_TAG() == 0) { e = rb_funcall(errinfo, rb_intern("message"), 0, 0); StringValue(e); einfo = RSTRING_PTR(e); elen = RSTRING_LEN(e); } else { einfo = ""; elen = 0; } if (EXEC_TAG()) goto error; if (eclass == rb_eRuntimeError && elen == 0) { warn_print(": unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print(": "); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print("\n"); } else { char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print(": "); warn_print2(einfo, len); if (epath) { warn_print(" ("); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print(")\n"); } if (tail) { warn_print2(tail, elen - len - 1); if (einfo[elen-1] != '\n') warn_print2("\n", 1); } } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); VALUE *ptr = RARRAY_PTR(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { if (TYPE(ptr[i]) == T_STRING) { warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i])); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_printf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL); i = len - TRACE_TAIL; } } } error: POP_TAG(); }
// Macro Processing Loop, called from the periodic execution thread // Called once per USB buffer send void Macro_periodic() { // Latency measurement Latency_start_time( macroLatencyResource ); #if defined(ConnectEnabled_define) // Only compile in if a Connect node module is available // If this is a interconnect slave node, send all scancodes to master node if ( !Connect_master ) { if ( macroTriggerEventBufferSize > 0 ) { Connect_send_ScanCode( Connect_id, macroTriggerEventBuffer, macroTriggerEventBufferSize ); macroTriggerEventBufferSize = 0; } return; } #endif #if defined(ConnectEnabled_define) || defined(PressReleaseCache_define) #if defined(ConnectEnabled_define) // Check if there are any ScanCodes in the interconnect cache to process if ( Connect_master && macroInterconnectCacheSize > 0 ) #endif { // Iterate over all the cache ScanCodes uint8_t currentInterconnectCacheSize = macroInterconnectCacheSize; macroInterconnectCacheSize = 0; for ( uint8_t c = 0; c < currentInterconnectCacheSize; c++ ) { // Add to the trigger list macroTriggerEventBuffer[ macroTriggerEventBufferSize++ ] = macroInterconnectCache[ c ]; // TODO Handle other TriggerGuide types (e.g. analog) switch ( macroInterconnectCache[ c ].type ) { // Normal (Press/Hold/Release) case TriggerType_Switch1: case TriggerType_Switch2: case TriggerType_Switch3: case TriggerType_Switch4: case TriggerType_LED1: // Decide what to do based on the current state switch ( macroInterconnectCache[ c ].state ) { // Re-add to interconnect cache in hold state case ScheduleType_P: // Press //case ScheduleType_H: // Hold // XXX Why does this not work? -HaaTa macroInterconnectCache[ c ].state = ScheduleType_H; macroInterconnectCache[ macroInterconnectCacheSize++ ] = macroInterconnectCache[ c ]; break; case ScheduleType_R: // Release break; // Otherwise, do not re-add default: break; } break; // Not implemented default: erro_msg("Interconnect Trigger Event Type - Not Implemented "); printInt8( macroInterconnectCache[ c ].type ); print( NL ); break; } } } #endif // Macro incoming state debug switch ( macroDebugMode ) { case 1: case 2: // Iterate over incoming triggers for ( uint16_t trigger = 0; trigger < macroTriggerEventBufferSize; trigger++ ) { // Show debug info about incoming trigger Macro_showTriggerEvent( ¯oTriggerEventBuffer[trigger] ); print( NL ); } case 3: default: break; } // Check macroTriggerEventBufferSize to make sure no overflow if ( macroTriggerEventBufferSize >= MaxScanCode_KLL ) { // No scancodes defined if ( MaxScanCode_KLL == 0 ) { warn_print("No scancodes defined! Check your BaseMap!"); } // Bug! else { erro_msg("Macro Trigger Event Overflow! Serious Bug! "); printInt16( macroTriggerEventBufferSize ); print( NL ); macroTriggerEventBufferSize = 0; } } // If the pause flag is set, only process if the step counter is non-zero if ( macroPauseMode ) { if ( macroStepCounter == 0 ) return; // Proceed, decrementing the step counter macroStepCounter--; dbug_print("Macro Step"); } // Process Trigger Macros Trigger_process(); // Store events processed var_uint_t macroTriggerEventBufferSize_processed = macroTriggerEventBufferSize; // Reset TriggerList buffer macroTriggerEventBufferSize = 0; // Process result macros Result_process(); // Signal buffer that we've used it Scan_finishedWithMacro( macroTriggerEventBufferSize_processed ); #if defined(_host_) // Signal host to read layer state Output_callback( "layerState", "" ); #endif // Latency measurement Latency_end_time( macroLatencyResource ); // If Macro debug mode is set, clear the USB Buffer #if defined(Output_USBEnabled_define) if ( macroDebugMode == 1 || macroDebugMode == 3 ) { USBKeys_primary.changed = 0; } #endif }
void cliFunc_capSelect( char* args ) { // Parse code from argument char* curArgs; char* arg1Ptr; char* arg2Ptr = args; // Total number of args to scan (must do a lookup if a keyboard capability is selected) var_uint_t totalArgs = 2; // Always at least two args var_uint_t cap = 0; // Arguments used for keyboard capability function var_uint_t argSetCount = 0; uint8_t *argSet = (uint8_t*)args; // Process all args for ( var_uint_t c = 0; argSetCount < totalArgs; c++ ) { curArgs = arg2Ptr; CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr ); // Stop processing args if no more are found // Extra arguments are ignored if ( *arg1Ptr == '\0' ) break; // For the first argument, choose the capability if ( c == 0 ) switch ( arg1Ptr[0] ) { // Keyboard Capability case 'K': // Determine capability index cap = numToInt( &arg1Ptr[1] ); // Lookup the number of args totalArgs += CapabilitiesList[ cap ].argCount; continue; } // Because allocating memory isn't doable, and the argument count is arbitrary // The argument pointer is repurposed as the argument list (much smaller anyways) argSet[ argSetCount++ ] = (uint8_t)numToInt( arg1Ptr ); // Once all the arguments are prepared, call the keyboard capability function if ( argSetCount == totalArgs ) { // Indicate that the capability was called print( NL ); info_msg("K"); printInt8( cap ); print(" - "); printHex( argSet[0] ); print(" - "); printHex( argSet[1] ); print(" - "); printHex( argSet[2] ); print( "..." NL ); // Make sure this isn't the reload capability // If it is, and the remote reflash define is not set, ignore if ( flashModeEnabled_define == 0 ) for ( uint32_t cap = 0; cap < CapabilitiesNum; cap++ ) { if ( CapabilitiesList[ cap ].func == (const void*)Output_flashMode_capability ) { print( NL ); warn_print("flashModeEnabled not set, cancelling firmware reload..."); info_msg("Set flashModeEnabled to 1 in your kll configuration."); return; } } void (*capability)(TriggerMacro*, uint8_t, uint8_t, uint8_t*) = \ (void(*)(TriggerMacro*, uint8_t, uint8_t, uint8_t*))(CapabilitiesList[ cap ].func); capability( 0, argSet[0], argSet[1], &argSet[2] ); } } }
// Adds a single USB Code to the USB Output buffer // Argument #1: USB Code void Output_usbCodeSend_capability( uint8_t state, uint8_t stateType, uint8_t *args ) { // Display capability name if ( stateType == 0xFF && state == 0xFF ) { print("Output_usbCodeSend(usbCode)"); return; } // Depending on which mode the keyboard is in the USB needs Press/Hold/Release events uint8_t keyPress = 0; // Default to key release, only used for NKRO switch ( USBKeys_Protocol ) { case 0: // Boot Mode // TODO Analog inputs // Only indicate USB has changed if either a press or release has occured if ( state == 0x01 || state == 0x03 ) USBKeys_Changed = USBKeyChangeState_MainKeys; // Only send keypresses if press or hold state if ( stateType == 0x00 && state == 0x03 ) // Release state return; break; case 1: // NKRO Mode // Only send press and release events if ( stateType == 0x00 && state == 0x02 ) // Hold state return; // Determine if setting or unsetting the bitfield (press == set) if ( stateType == 0x00 && state == 0x01 ) // Press state keyPress = 1; break; } // Get the keycode from arguments uint8_t key = args[0]; // Depending on which mode the keyboard is in, USBKeys_Keys array is used differently // Boot mode - Maximum of 6 byte codes // NKRO mode - Each bit of the 26 byte corresponds to a key // Bits 0 - 45 (bytes 0 - 5) correspond to USB Codes 4 - 49 (Main) // Bits 48 - 161 (bytes 6 - 20) correspond to USB Codes 51 - 164 (Secondary) // Bits 168 - 213 (bytes 21 - 26) correspond to USB Codes 176 - 221 (Tertiary) // Bits 214 - 216 unused uint8_t bytePosition = 0; uint8_t byteShift = 0; switch ( USBKeys_Protocol ) { case 0: // Boot Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } // Normal USB Code else { // USB Key limit reached if ( USBKeys_Sent >= USB_BOOT_MAX_KEYS ) { warn_print("USB Key limit reached"); return; } // Make sure key is within the USB HID range if ( key <= 104 ) { USBKeys_Keys[USBKeys_Sent++] = key; } // Invalid key else { warn_msg("USB Code above 104/0x68 in Boot Mode: "); printHex( key ); print( NL ); } } break; case 1: // NKRO Mode // Set the modifier bit if this key is a modifier if ( (key & 0xE0) == 0xE0 ) // AND with 0xE0 (Left Ctrl, first modifier) { if ( keyPress ) { USBKeys_Modifiers |= 1 << (key ^ 0xE0); // Left shift 1 by key XOR 0xE0 } else // Release { USBKeys_Modifiers &= ~(1 << (key ^ 0xE0)); // Left shift 1 by key XOR 0xE0 } USBKeys_Changed |= USBKeyChangeState_Modifiers; break; } // First 6 bytes else if ( key >= 4 && key <= 49 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 0th position, each byte has 8 bits, starting at 4th bit uint8_t keyPos = key + (0 * 8 - 4); // Starting position in array, Ignoring 4 keys switch ( keyPos ) { byteLookup( 0 ); byteLookup( 1 ); byteLookup( 2 ); byteLookup( 3 ); byteLookup( 4 ); byteLookup( 5 ); } USBKeys_Changed |= USBKeyChangeState_MainKeys; } // Next 14 bytes else if ( key >= 51 && key <= 155 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) // Starting at 6th byte position, each byte has 8 bits, starting at 51st bit uint8_t keyPos = key + (6 * 8 - 51); // Starting position in array switch ( keyPos ) { byteLookup( 6 ); byteLookup( 7 ); byteLookup( 8 ); byteLookup( 9 ); byteLookup( 10 ); byteLookup( 11 ); byteLookup( 12 ); byteLookup( 13 ); byteLookup( 14 ); byteLookup( 15 ); byteLookup( 16 ); byteLookup( 17 ); byteLookup( 18 ); byteLookup( 19 ); } USBKeys_Changed |= USBKeyChangeState_SecondaryKeys; } // Next byte else if ( key >= 157 && key <= 164 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (20 * 8 - 157); // Starting position in array, Ignoring 6 keys switch ( keyPos ) { byteLookup( 20 ); } USBKeys_Changed |= USBKeyChangeState_TertiaryKeys; } // Last 6 bytes else if ( key >= 176 && key <= 221 ) { // Lookup (otherwise division or multiple checks are needed to do alignment) uint8_t keyPos = key + (21 * 8 - 176); // Starting position in array switch ( keyPos ) { byteLookup( 21 ); byteLookup( 22 ); byteLookup( 23 ); byteLookup( 24 ); byteLookup( 25 ); byteLookup( 26 ); } USBKeys_Changed |= USBKeyChangeState_QuartiaryKeys; } // Received 0x00 // This is a special USB Code that internally indicates a "break" // It is used to send "nothing" in order to break up sequences of USB Codes else if ( key == 0x00 ) { USBKeys_Changed |= USBKeyChangeState_MainKeys; // Also flush out buffers just in case Output_flushBuffers(); break; } // Invalid key else { warn_msg("USB Code not within 4-49 (0x4-0x31), 51-155 (0x33-0x9B), 157-164 (0x9D-0xA4), 176-221 (0xB0-0xDD) or 224-231 (0xE0-0xE7) NKRO Mode: "); printHex( key ); print( NL ); break; } // Set/Unset if ( keyPress ) { USBKeys_Keys[bytePosition] |= (1 << byteShift); USBKeys_Sent++; } else // Release { USBKeys_Keys[bytePosition] &= ~(1 << byteShift); USBKeys_Sent++; } break; } }
void rb_threadptr_error_print(rb_thread_t *th, VALUE errinfo) { volatile VALUE errat = Qundef; int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, e = Qundef; const char *volatile einfo; volatile long elen; VALUE mesg; if (NIL_P(errinfo)) return; rb_thread_raised_clear(th); TH_PUSH_TAG(th); if (TH_EXEC_TAG() == 0) { errat = rb_get_backtrace(errinfo); } else if (errat == Qundef) { errat = Qnil; } else if (eclass == Qundef || e != Qundef) { goto error; } else { goto no_message; } if (NIL_P(errat) || RARRAY_LEN(errat) == 0 || NIL_P(mesg = RARRAY_AREF(errat, 0))) { error_pos(); } else { warn_print_str(mesg); warn_print(": "); } eclass = CLASS_OF(errinfo); if (eclass != Qundef && (e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0)) != Qundef && (RB_TYPE_P(e, T_STRING) || !NIL_P(e = rb_check_string_type(e)))) { einfo = RSTRING_PTR(e); elen = RSTRING_LEN(e); } else { no_message: einfo = ""; elen = 0; } if (eclass == rb_eRuntimeError && elen == 0) { warn_print("unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print_str(epath); warn_print("\n"); } else { const char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print_str(tail ? rb_str_subseq(e, 0, len) : e); if (epath) { warn_print(" ("); warn_print_str(epath); warn_print(")\n"); } if (tail) { warn_print_str(rb_str_subseq(e, tail - einfo, elen - len - 1)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { VALUE line = RARRAY_AREF(errat, i); if (RB_TYPE_P(line, T_STRING)) { warn_print_str(rb_sprintf("\tfrom %"PRIsVALUE"\n", line)); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_print_str(rb_sprintf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL)); i = len - TRACE_TAIL; } } } error: TH_POP_TAG(); th->errinfo = errinfo; rb_thread_raised_set(th, raised_flag); }
int32_t i2c_send_sequence( uint8_t ch, uint16_t *sequence, uint32_t sequence_length, uint8_t *received_data, void ( *callback_fn )( void* ), void *user_data ) { int32_t result = 0; volatile I2C_Channel *channel = &( i2c_channels[ch - ISSI_I2C_FirstBus_define] ); uint8_t address; #if defined(_kinetis_) uint8_t status; volatile uint8_t *I2C_C1 = (uint8_t*)(&I2C0_C1) + i2c_offset[ch]; volatile uint8_t *I2C_S = (uint8_t*)(&I2C0_S) + i2c_offset[ch]; volatile uint8_t *I2C_D = (uint8_t*)(&I2C0_D) + i2c_offset[ch]; #elif defined(_sam_) Twi *twi_dev = twi_devs[ch]; #endif if ( channel->status == I2C_BUSY ) { return -1; } // Check if there are back-to-back errors // in succession if ( channel->last_error > 5 ) { warn_msg("I2C Bus Error: "); printInt8( ch ); print(" errors: "); printInt32( channel->error_count ); print( NL ); } // Debug /* for ( uint8_t c = 0; c < sequence_length; c++ ) { printHex( sequence[c] ); print(" "); } print(NL); */ channel->sequence = sequence; channel->sequence_end = sequence + sequence_length; channel->received_data = received_data; channel->status = I2C_BUSY; channel->txrx = I2C_WRITING; channel->callback_fn = callback_fn; channel->user_data = user_data; // reads_ahead does not need to be initialized #if defined(_kinetis_) // Acknowledge the interrupt request, just in case *I2C_S |= I2C_S_IICIF; *I2C_C1 = ( I2C_C1_IICEN | I2C_C1_IICIE ); // Generate a start condition and prepare for transmitting. *I2C_C1 |= ( I2C_C1_MST | I2C_C1_TX ); status = *I2C_S; if ( status & I2C_S_ARBL ) { warn_print("Arbitration lost"); result = -1; goto i2c_send_sequence_cleanup; } // Write the first (address) byte. address = *channel->sequence++; *I2C_D = address; // Everything is OK. return result; i2c_send_sequence_cleanup: // Record error, and reset last error counter channel->error_count++; channel->last_error++; // Generate STOP and disable further interrupts. *I2C_C1 &= ~( I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX ); channel->status = I2C_ERROR; #elif defined(_sam_) // Convert 8 bit address to 7bit + RW address = *channel->sequence++; //print("Address: "); //printHex( address ); //print( NL ); uint8_t mread = address & 1; address >>= 1; // Set slave address twi_dev->TWI_MMR = TWI_MMR_DADR(address) | (mread ? TWI_MMR_MREAD : 0); // Enable interrupts twi_dev->TWI_IER = TWI_IER_RXRDY | TWI_IER_TXRDY | TWI_IER_TXCOMP | TWI_IER_ARBLST; //twi_dev->TWI_IDR = 0xFFFFFFFF; // Generate a start condition twi_dev->TWI_CR |= TWI_CR_START; // Fire off the first read or write. // The first (address) byte is automatically trasmitted before any data // Arbitration errors will be handled in the isr i2c_isr(ch); // Everything is OK. return result; #endif return result; }