mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-30 21:02:32 +01:00 
			
		
		
		
	Remove leftover old implementations of the lily58 split code. (#12442)
This commit is contained in:
		
							parent
							
								
									8a950a7116
								
							
						
					
					
						commit
						c5ddada32e
					
				| @ -35,6 +35,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | |||||||
| #define MATRIX_ROW_PINS { C6, D7, E6, B4, B5 } | #define MATRIX_ROW_PINS { C6, D7, E6, B4, B5 } | ||||||
| #define MATRIX_COL_PINS { F6, F7, B1, B3, B2, B6 } | #define MATRIX_COL_PINS { F6, F7, B1, B3, B2, B6 } | ||||||
| 
 | 
 | ||||||
|  | #define SOFT_SERIAL_PIN D2 | ||||||
|  | #define SERIAL_USE_MULTI_TRANSACTION | ||||||
| 
 | 
 | ||||||
| /* define if matrix has ghost */ | /* define if matrix has ghost */ | ||||||
| //#define MATRIX_HAS_GHOST
 | //#define MATRIX_HAS_GHOST
 | ||||||
|  | |||||||
| @ -1,357 +0,0 @@ | |||||||
| /*
 |  | ||||||
| Copyright 2012 Jun Wako <wakojun@gmail.com> |  | ||||||
| 
 |  | ||||||
| This program is free software: you can redistribute it and/or modify |  | ||||||
| it under the terms of the GNU General Public License as published by |  | ||||||
| the Free Software Foundation, either version 2 of the License, or |  | ||||||
| (at your option) any later version. |  | ||||||
| 
 |  | ||||||
| This program is distributed in the hope that it will be useful, |  | ||||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
| GNU General Public License for more details. |  | ||||||
| 
 |  | ||||||
| You should have received a copy of the GNU General Public License |  | ||||||
| along with this program.  If not, see <http://www.gnu.org/licenses/>.
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * scan matrix |  | ||||||
|  */ |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <avr/io.h> |  | ||||||
| #include <avr/wdt.h> |  | ||||||
| #include <avr/interrupt.h> |  | ||||||
| #include <util/delay.h> |  | ||||||
| #include "print.h" |  | ||||||
| #include "debug.h" |  | ||||||
| #include "util.h" |  | ||||||
| #include "matrix.h" |  | ||||||
| #include "split_util.h" |  | ||||||
| #include "quantum.h" |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
| #  include "i2c.h" |  | ||||||
| #else // USE_SERIAL
 |  | ||||||
| #  include "split_scomm.h" |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef DEBOUNCE |  | ||||||
| #  define DEBOUNCE	5 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #define ERROR_DISCONNECT_COUNT 5 |  | ||||||
| 
 |  | ||||||
| static uint8_t debouncing = DEBOUNCE; |  | ||||||
| static const int ROWS_PER_HAND = MATRIX_ROWS/2; |  | ||||||
| static uint8_t error_count = 0; |  | ||||||
| uint8_t is_master = 0 ; |  | ||||||
| 
 |  | ||||||
| static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; |  | ||||||
| static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; |  | ||||||
| 
 |  | ||||||
| /* matrix state(1:on, 0:off) */ |  | ||||||
| static matrix_row_t matrix[MATRIX_ROWS]; |  | ||||||
| static matrix_row_t matrix_debouncing[MATRIX_ROWS]; |  | ||||||
| 
 |  | ||||||
| static matrix_row_t read_cols(void); |  | ||||||
| static void init_cols(void); |  | ||||||
| static void unselect_rows(void); |  | ||||||
| static void select_row(uint8_t row); |  | ||||||
| static uint8_t matrix_master_scan(void); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| __attribute__ ((weak)) |  | ||||||
| void matrix_init_kb(void) { |  | ||||||
|     matrix_init_user(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| __attribute__ ((weak)) |  | ||||||
| void matrix_scan_kb(void) { |  | ||||||
|     matrix_scan_user(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| __attribute__ ((weak)) |  | ||||||
| void matrix_init_user(void) { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| __attribute__ ((weak)) |  | ||||||
| void matrix_scan_user(void) { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline |  | ||||||
| uint8_t matrix_rows(void) |  | ||||||
| { |  | ||||||
|     return MATRIX_ROWS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline |  | ||||||
| uint8_t matrix_cols(void) |  | ||||||
| { |  | ||||||
|     return MATRIX_COLS; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void matrix_init(void) |  | ||||||
| { |  | ||||||
|     split_keyboard_setup(); |  | ||||||
| 
 |  | ||||||
|     // initialize row and col
 |  | ||||||
|     unselect_rows(); |  | ||||||
|     init_cols(); |  | ||||||
| 
 |  | ||||||
|     setPinOutput(B0); |  | ||||||
|     setPinOutput(D5); |  | ||||||
|     writePinHigh(B0); |  | ||||||
|     writePinHigh(D5); |  | ||||||
| 
 |  | ||||||
|     // initialize matrix state: all keys off
 |  | ||||||
|     for (uint8_t i=0; i < MATRIX_ROWS; i++) { |  | ||||||
|         matrix[i] = 0; |  | ||||||
|         matrix_debouncing[i] = 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     is_master = has_usb(); |  | ||||||
| 
 |  | ||||||
|     matrix_init_quantum(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t _matrix_scan(void) |  | ||||||
| { |  | ||||||
|     // Right hand is stored after the left in the matirx so, we need to offset it
 |  | ||||||
|     int offset = isLeftHand ? 0 : (ROWS_PER_HAND); |  | ||||||
| 
 |  | ||||||
|     for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { |  | ||||||
|         select_row(i); |  | ||||||
|         _delay_us(30);  // without this wait read unstable value.
 |  | ||||||
|         matrix_row_t cols = read_cols(); |  | ||||||
|         if (matrix_debouncing[i+offset] != cols) { |  | ||||||
|             matrix_debouncing[i+offset] = cols; |  | ||||||
|             debouncing = DEBOUNCE; |  | ||||||
|         } |  | ||||||
|         unselect_rows(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (debouncing) { |  | ||||||
|         if (--debouncing) { |  | ||||||
|             _delay_ms(1); |  | ||||||
|         } else { |  | ||||||
|             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { |  | ||||||
|                 matrix[i+offset] = matrix_debouncing[i+offset]; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
| 
 |  | ||||||
| // Get rows from other half over i2c
 |  | ||||||
| int i2c_transaction(void) { |  | ||||||
|     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; |  | ||||||
| 
 |  | ||||||
|     int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); |  | ||||||
|     if (err) goto i2c_error; |  | ||||||
| 
 |  | ||||||
|     // start of matrix stored at 0x00
 |  | ||||||
|     err = i2c_master_write(0x00); |  | ||||||
|     if (err) goto i2c_error; |  | ||||||
| 
 |  | ||||||
|     // Start read
 |  | ||||||
|     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); |  | ||||||
|     if (err) goto i2c_error; |  | ||||||
| 
 |  | ||||||
|     if (!err) { |  | ||||||
|         int i; |  | ||||||
|         for (i = 0; i < ROWS_PER_HAND-1; ++i) { |  | ||||||
|             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); |  | ||||||
|         } |  | ||||||
|         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK); |  | ||||||
|         i2c_master_stop(); |  | ||||||
|     } else { |  | ||||||
| i2c_error: // the cable is disconnceted, or something else went wrong
 |  | ||||||
|         i2c_reset_state(); |  | ||||||
|         return err; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #else // USE_SERIAL
 |  | ||||||
| 
 |  | ||||||
| int serial_transaction(int master_changed) { |  | ||||||
|     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; |  | ||||||
| #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|     int ret=serial_update_buffers(master_changed); |  | ||||||
| #else |  | ||||||
|     int ret=serial_update_buffers(); |  | ||||||
| #endif |  | ||||||
|     if (ret ) { |  | ||||||
|         if(ret==2) writePinLow(B0); |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
|     writePinHigh(B0); |  | ||||||
|     memcpy(&matrix[slaveOffset], |  | ||||||
|         (void *)serial_slave_buffer, SERIAL_SLAVE_BUFFER_LENGTH); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| uint8_t matrix_scan(void) |  | ||||||
| { |  | ||||||
|     if (is_master) { |  | ||||||
|         matrix_master_scan(); |  | ||||||
|     }else{ |  | ||||||
|         matrix_slave_scan(); |  | ||||||
|         int offset = (isLeftHand) ? ROWS_PER_HAND : 0; |  | ||||||
|         memcpy(&matrix[offset], |  | ||||||
|                (void *)serial_master_buffer, SERIAL_MASTER_BUFFER_LENGTH); |  | ||||||
|         matrix_scan_quantum(); |  | ||||||
|     } |  | ||||||
|     return 1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| uint8_t matrix_master_scan(void) { |  | ||||||
| 
 |  | ||||||
|     int ret = _matrix_scan(); |  | ||||||
|     int mchanged = 1; |  | ||||||
| 
 |  | ||||||
|     int offset = (isLeftHand) ? 0 : ROWS_PER_HAND; |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
| //    for (int i = 0; i < ROWS_PER_HAND; ++i) {
 |  | ||||||
|         /* i2c_slave_buffer[i] = matrix[offset+i]; */ |  | ||||||
| //        i2c_slave_buffer[i] = matrix[offset+i];
 |  | ||||||
| //    }
 |  | ||||||
| #else // USE_SERIAL
 |  | ||||||
|   #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|     mchanged = memcmp((void *)serial_master_buffer, |  | ||||||
| 		      &matrix[offset], SERIAL_MASTER_BUFFER_LENGTH); |  | ||||||
|   #endif |  | ||||||
|     memcpy((void *)serial_master_buffer, |  | ||||||
| 	   &matrix[offset], SERIAL_MASTER_BUFFER_LENGTH); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
|     if( i2c_transaction() ) { |  | ||||||
| #else // USE_SERIAL
 |  | ||||||
|     if( serial_transaction(mchanged) ) { |  | ||||||
| #endif |  | ||||||
|         // turn on the indicator led when halves are disconnected
 |  | ||||||
|         writePinLow(D5); |  | ||||||
| 
 |  | ||||||
|         error_count++; |  | ||||||
| 
 |  | ||||||
|         if (error_count > ERROR_DISCONNECT_COUNT) { |  | ||||||
|             // reset other half if disconnected
 |  | ||||||
|             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; |  | ||||||
|             for (int i = 0; i < ROWS_PER_HAND; ++i) { |  | ||||||
|                 matrix[slaveOffset+i] = 0; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // turn off the indicator led on no error
 |  | ||||||
|         writePinHigh(D5); |  | ||||||
|         error_count = 0; |  | ||||||
|     } |  | ||||||
|     matrix_scan_quantum(); |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void matrix_slave_scan(void) { |  | ||||||
|     _matrix_scan(); |  | ||||||
| 
 |  | ||||||
|     int offset = (isLeftHand) ? 0 : ROWS_PER_HAND; |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
|     for (int i = 0; i < ROWS_PER_HAND; ++i) { |  | ||||||
|         /* i2c_slave_buffer[i] = matrix[offset+i]; */ |  | ||||||
|         i2c_slave_buffer[i] = matrix[offset+i]; |  | ||||||
|     } |  | ||||||
| #else // USE_SERIAL
 |  | ||||||
|   #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|     int change = 0; |  | ||||||
|   #endif |  | ||||||
|     for (int i = 0; i < ROWS_PER_HAND; ++i) { |  | ||||||
|   #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|         if( serial_slave_buffer[i] != matrix[offset+i] ) |  | ||||||
| 	    change = 1; |  | ||||||
|   #endif |  | ||||||
|         serial_slave_buffer[i] = matrix[offset+i]; |  | ||||||
|     } |  | ||||||
|   #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|     slave_buffer_change_count += change; |  | ||||||
|   #endif |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool matrix_is_modified(void) |  | ||||||
| { |  | ||||||
|     if (debouncing) return false; |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline |  | ||||||
| bool matrix_is_on(uint8_t row, uint8_t col) |  | ||||||
| { |  | ||||||
|     return (matrix[row] & ((matrix_row_t)1<<col)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline |  | ||||||
| matrix_row_t matrix_get_row(uint8_t row) |  | ||||||
| { |  | ||||||
|     return matrix[row]; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void matrix_print(void) |  | ||||||
| { |  | ||||||
|     print("\nr/c 0123456789ABCDEF\n"); |  | ||||||
|     for (uint8_t row = 0; row < MATRIX_ROWS; row++) { |  | ||||||
|         print_hex8(row); print(": "); |  | ||||||
|         print_bin_reverse16(matrix_get_row(row)); |  | ||||||
|         print("\n"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint8_t matrix_key_count(void) |  | ||||||
| { |  | ||||||
|     uint8_t count = 0; |  | ||||||
|     for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |  | ||||||
|         count += bitpop16(matrix[i]); |  | ||||||
|     } |  | ||||||
|     return count; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void  init_cols(void) |  | ||||||
| { |  | ||||||
|     for(int x = 0; x < MATRIX_COLS; x++) { |  | ||||||
|         _SFR_IO8((col_pins[x] >> 4) + 1) &=  ~_BV(col_pins[x] & 0xF); |  | ||||||
|         _SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static matrix_row_t read_cols(void) |  | ||||||
| { |  | ||||||
|     matrix_row_t result = 0; |  | ||||||
|     for(int x = 0; x < MATRIX_COLS; x++) { |  | ||||||
|         result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x); |  | ||||||
|     } |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void unselect_rows(void) |  | ||||||
| { |  | ||||||
|     for(int x = 0; x < ROWS_PER_HAND; x++) { |  | ||||||
|         _SFR_IO8((row_pins[x] >> 4) + 1) &=  ~_BV(row_pins[x] & 0xF); |  | ||||||
|         _SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void select_row(uint8_t row) |  | ||||||
| { |  | ||||||
|     _SFR_IO8((row_pins[row] >> 4) + 1) |=  _BV(row_pins[row] & 0xF); |  | ||||||
|     _SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF); |  | ||||||
| } |  | ||||||
| @ -1,4 +0,0 @@ | |||||||
| #ifndef SOFT_SERIAL_PIN |  | ||||||
| #define SOFT_SERIAL_PIN D2 |  | ||||||
| #define SERIAL_USE_MULTI_TRANSACTION |  | ||||||
| #endif |  | ||||||
| @ -1,100 +0,0 @@ | |||||||
| #include <avr/io.h> |  | ||||||
| #include <avr/wdt.h> |  | ||||||
| #include <avr/power.h> |  | ||||||
| #include <avr/interrupt.h> |  | ||||||
| #include <util/delay.h> |  | ||||||
| #include <avr/eeprom.h> |  | ||||||
| #include "split_util.h" |  | ||||||
| #include "matrix.h" |  | ||||||
| #include "keyboard.h" |  | ||||||
| #include "wait.h" |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
| #  include "i2c.h" |  | ||||||
| #else |  | ||||||
| #  include "split_scomm.h" |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #ifndef SPLIT_USB_TIMEOUT |  | ||||||
| #    define SPLIT_USB_TIMEOUT 2500 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| volatile bool isLeftHand = true; |  | ||||||
| 
 |  | ||||||
| bool waitForUsb(void) { |  | ||||||
|     for (uint8_t i = 0; i < (SPLIT_USB_TIMEOUT / 100); i++) { |  | ||||||
|         // This will return true of a USB connection has been established
 |  | ||||||
|         if (UDADDR & _BV(ADDEN)) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         wait_ms(100); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Avoid NO_USB_STARTUP_CHECK - Disable USB as the previous checks seem to enable it somehow
 |  | ||||||
|     (USBCON &= ~(_BV(USBE) | _BV(OTGPADE))); |  | ||||||
| 
 |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| __attribute__((weak)) bool is_keyboard_left(void) { |  | ||||||
| #if defined(SPLIT_HAND_PIN) |  | ||||||
|     // Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand
 |  | ||||||
|     setPinInput(SPLIT_HAND_PIN); |  | ||||||
|     return readPin(SPLIT_HAND_PIN); |  | ||||||
| #elif defined(EE_HANDS) |  | ||||||
|     return eeconfig_read_handedness(); |  | ||||||
| #elif defined(MASTER_RIGHT) |  | ||||||
|     return !has_usb(); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     return has_usb(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| __attribute__((weak)) bool has_usb(void) { |  | ||||||
|     static enum { UNKNOWN, MASTER, SLAVE } usbstate = UNKNOWN; |  | ||||||
| 
 |  | ||||||
|     // only check once, as this is called often
 |  | ||||||
|     if (usbstate == UNKNOWN) { |  | ||||||
| #if defined(SPLIT_USB_DETECT) |  | ||||||
|         usbstate = waitForUsb() ? MASTER : SLAVE; |  | ||||||
| #elif defined(__AVR__) |  | ||||||
|         USBCON |= (1 << OTGPADE);  // enables VBUS pad
 |  | ||||||
|         wait_us(5); |  | ||||||
| 
 |  | ||||||
|         usbstate = (USBSTA & (1 << VBUS)) ? MASTER : SLAVE;  // checks state of VBUS
 |  | ||||||
| #else |  | ||||||
|         usbstate = MASTER; |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return (usbstate == MASTER); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void keyboard_master_setup(void) { |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
|     i2c_master_init(); |  | ||||||
| #else |  | ||||||
|     serial_master_init(); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void keyboard_slave_setup(void) { |  | ||||||
| 
 |  | ||||||
| #ifdef USE_MATRIX_I2C |  | ||||||
|     i2c_slave_init(SLAVE_I2C_ADDRESS); |  | ||||||
| #else |  | ||||||
|     serial_slave_init(); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void split_keyboard_setup(void) { |  | ||||||
|    isLeftHand = is_keyboard_left(); |  | ||||||
| 
 |  | ||||||
|    if (has_usb()) { |  | ||||||
|       keyboard_master_setup(); |  | ||||||
|    } else { |  | ||||||
|       keyboard_slave_setup(); |  | ||||||
|    } |  | ||||||
|    sei(); |  | ||||||
| } |  | ||||||
| @ -1,589 +0,0 @@ | |||||||
| /*
 |  | ||||||
|  * WARNING: be careful changing this code, it is very timing dependent |  | ||||||
|  * |  | ||||||
|  * 2018-10-28 checked |  | ||||||
|  *  avr-gcc 4.9.2 |  | ||||||
|  *  avr-gcc 5.4.0 |  | ||||||
|  *  avr-gcc 7.3.0 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| #ifndef F_CPU |  | ||||||
| #define F_CPU 16000000 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include <avr/io.h> |  | ||||||
| #include <avr/interrupt.h> |  | ||||||
| #include <util/delay.h> |  | ||||||
| #include <stddef.h> |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include "serial.h" |  | ||||||
| 
 |  | ||||||
| #ifdef SOFT_SERIAL_PIN |  | ||||||
| 
 |  | ||||||
| #ifdef __AVR_ATmega32U4__ |  | ||||||
|   // if using ATmega32U4 I2C, can not use PD0 and PD1 in soft serial.
 |  | ||||||
|   #ifdef USE_I2C |  | ||||||
|     #if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1 |  | ||||||
|       #error Using ATmega32U4 I2C, so can not use PD0, PD1 |  | ||||||
|     #endif |  | ||||||
|   #endif |  | ||||||
| 
 |  | ||||||
|   #if SOFT_SERIAL_PIN >= D0 && SOFT_SERIAL_PIN <= D3 |  | ||||||
|     #define SERIAL_PIN_DDR   DDRD |  | ||||||
|     #define SERIAL_PIN_PORT  PORTD |  | ||||||
|     #define SERIAL_PIN_INPUT PIND |  | ||||||
|     #if SOFT_SERIAL_PIN == D0 |  | ||||||
|       #define SERIAL_PIN_MASK _BV(PD0) |  | ||||||
|       #define EIMSK_BIT       _BV(INT0) |  | ||||||
|       #define EICRx_BIT       (~(_BV(ISC00) | _BV(ISC01))) |  | ||||||
|       #define SERIAL_PIN_INTERRUPT INT0_vect |  | ||||||
|     #elif  SOFT_SERIAL_PIN == D1 |  | ||||||
|       #define SERIAL_PIN_MASK _BV(PD1) |  | ||||||
|       #define EIMSK_BIT       _BV(INT1) |  | ||||||
|       #define EICRx_BIT       (~(_BV(ISC10) | _BV(ISC11))) |  | ||||||
|       #define SERIAL_PIN_INTERRUPT INT1_vect |  | ||||||
|     #elif  SOFT_SERIAL_PIN == D2 |  | ||||||
|       #define SERIAL_PIN_MASK _BV(PD2) |  | ||||||
|       #define EIMSK_BIT       _BV(INT2) |  | ||||||
|       #define EICRx_BIT       (~(_BV(ISC20) | _BV(ISC21))) |  | ||||||
|       #define SERIAL_PIN_INTERRUPT INT2_vect |  | ||||||
|     #elif  SOFT_SERIAL_PIN == D3 |  | ||||||
|       #define SERIAL_PIN_MASK _BV(PD3) |  | ||||||
|       #define EIMSK_BIT       _BV(INT3) |  | ||||||
|       #define EICRx_BIT       (~(_BV(ISC30) | _BV(ISC31))) |  | ||||||
|       #define SERIAL_PIN_INTERRUPT INT3_vect |  | ||||||
|     #endif |  | ||||||
|   #elif  SOFT_SERIAL_PIN == E6 |  | ||||||
|     #define SERIAL_PIN_DDR   DDRE |  | ||||||
|     #define SERIAL_PIN_PORT  PORTE |  | ||||||
|     #define SERIAL_PIN_INPUT PINE |  | ||||||
|     #define SERIAL_PIN_MASK  _BV(PE6) |  | ||||||
|     #define EIMSK_BIT        _BV(INT6) |  | ||||||
|     #define EICRx_BIT        (~(_BV(ISC60) | _BV(ISC61))) |  | ||||||
|     #define SERIAL_PIN_INTERRUPT INT6_vect |  | ||||||
|   #else |  | ||||||
|   #error invalid SOFT_SERIAL_PIN value |  | ||||||
|   #endif |  | ||||||
| 
 |  | ||||||
| #else |  | ||||||
|  #error serial.c now support ATmega32U4 only |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| //////////////// for backward compatibility ////////////////////////////////
 |  | ||||||
| #ifndef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
| /* --- USE Simple API (OLD API, compatible with let's split serial.c) */ |  | ||||||
|   #if SERIAL_SLAVE_BUFFER_LENGTH > 0 |  | ||||||
|   uint8_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0}; |  | ||||||
|   #endif |  | ||||||
|   #if SERIAL_MASTER_BUFFER_LENGTH > 0 |  | ||||||
|   uint8_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0}; |  | ||||||
|   #endif |  | ||||||
|   uint8_t volatile status0 = 0; |  | ||||||
| 
 |  | ||||||
| SSTD_t transactions[] = { |  | ||||||
|     { (uint8_t *)&status0, |  | ||||||
|   #if SERIAL_MASTER_BUFFER_LENGTH > 0 |  | ||||||
|       sizeof(serial_master_buffer), (uint8_t *)serial_master_buffer, |  | ||||||
|   #else |  | ||||||
|       0, (uint8_t *)NULL, |  | ||||||
|   #endif |  | ||||||
|   #if SERIAL_SLAVE_BUFFER_LENGTH > 0 |  | ||||||
|       sizeof(serial_slave_buffer), (uint8_t *)serial_slave_buffer |  | ||||||
|   #else |  | ||||||
|       0, (uint8_t *)NULL, |  | ||||||
|   #endif |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void serial_master_init(void) |  | ||||||
| { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } |  | ||||||
| 
 |  | ||||||
| void serial_slave_init(void) |  | ||||||
| { soft_serial_target_init(transactions, TID_LIMIT(transactions)); } |  | ||||||
| 
 |  | ||||||
| // 0 => no error
 |  | ||||||
| // 1 => slave did not respond
 |  | ||||||
| // 2 => checksum error
 |  | ||||||
| int serial_update_buffers() |  | ||||||
| { |  | ||||||
|     int result; |  | ||||||
|     result = soft_serial_transaction(); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #endif // end of Simple API (OLD API, compatible with let's split serial.c)
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| #define ALWAYS_INLINE __attribute__((always_inline)) |  | ||||||
| #define NO_INLINE __attribute__((noinline)) |  | ||||||
| #define _delay_sub_us(x)    __builtin_avr_delay_cycles(x) |  | ||||||
| 
 |  | ||||||
| // parity check
 |  | ||||||
| #define ODD_PARITY 1 |  | ||||||
| #define EVEN_PARITY 0 |  | ||||||
| #define PARITY EVEN_PARITY |  | ||||||
| 
 |  | ||||||
| #ifdef SERIAL_DELAY |  | ||||||
|   // custom setup in config.h
 |  | ||||||
|   // #define TID_SEND_ADJUST 2
 |  | ||||||
|   // #define SERIAL_DELAY 6             // micro sec
 |  | ||||||
|   // #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|   // #define READ_WRITE_WIDTH_ADJUST 8 // cycles
 |  | ||||||
| #else |  | ||||||
| // ============ Standard setups ============
 |  | ||||||
| 
 |  | ||||||
| #ifndef SELECT_SOFT_SERIAL_SPEED |  | ||||||
| #define SELECT_SOFT_SERIAL_SPEED 1 |  | ||||||
| //  0: about 189kbps
 |  | ||||||
| //  1: about 137kbps (default)
 |  | ||||||
| //  2: about 75kbps
 |  | ||||||
| //  3: about 39kbps
 |  | ||||||
| //  4: about 26kbps
 |  | ||||||
| //  5: about 20kbps
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if __GNUC__ < 6 |  | ||||||
|   #define TID_SEND_ADJUST 14 |  | ||||||
| #else |  | ||||||
|   #define TID_SEND_ADJUST 2 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #if SELECT_SOFT_SERIAL_SPEED == 0 |  | ||||||
|   // Very High speed
 |  | ||||||
|   #define SERIAL_DELAY 4             // micro sec
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_START_ADJUST 33 // cycles
 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_START_ADJUST 34 // cycles
 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #elif SELECT_SOFT_SERIAL_SPEED == 1 |  | ||||||
|   // High speed
 |  | ||||||
|   #define SERIAL_DELAY 6             // micro sec
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_START_ADJUST 33 // cycles
 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #elif SELECT_SOFT_SERIAL_SPEED == 2 |  | ||||||
|   // Middle speed
 |  | ||||||
|   #define SERIAL_DELAY 12            // micro sec
 |  | ||||||
|   #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #elif SELECT_SOFT_SERIAL_SPEED == 3 |  | ||||||
|   // Low speed
 |  | ||||||
|   #define SERIAL_DELAY 24            // micro sec
 |  | ||||||
|   #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #elif SELECT_SOFT_SERIAL_SPEED == 4 |  | ||||||
|   // Very Low speed
 |  | ||||||
|   #define SERIAL_DELAY 36            // micro sec
 |  | ||||||
|   #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #elif SELECT_SOFT_SERIAL_SPEED == 5 |  | ||||||
|   // Ultra Low speed
 |  | ||||||
|   #define SERIAL_DELAY 48            // micro sec
 |  | ||||||
|   #define READ_WRITE_START_ADJUST 30 // cycles
 |  | ||||||
|   #if __GNUC__ < 6 |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 3 // cycles
 |  | ||||||
|   #else |  | ||||||
|     #define READ_WRITE_WIDTH_ADJUST 7 // cycles
 |  | ||||||
|   #endif |  | ||||||
| #else |  | ||||||
| #error invalid SELECT_SOFT_SERIAL_SPEED value |  | ||||||
| #endif /* SELECT_SOFT_SERIAL_SPEED */ |  | ||||||
| #endif /* SERIAL_DELAY */ |  | ||||||
| 
 |  | ||||||
| #define SERIAL_DELAY_HALF1 (SERIAL_DELAY/2) |  | ||||||
| #define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY/2) |  | ||||||
| 
 |  | ||||||
| #define SLAVE_INT_WIDTH_US 1 |  | ||||||
| #ifndef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|   #define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY |  | ||||||
| #else |  | ||||||
|   #define SLAVE_INT_ACK_WIDTH_UNIT 2 |  | ||||||
|   #define SLAVE_INT_ACK_WIDTH 4 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| static SSTD_t *Transaction_table = NULL; |  | ||||||
| static uint8_t Transaction_table_size = 0; |  | ||||||
| 
 |  | ||||||
| inline static void serial_delay(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_delay(void) { |  | ||||||
|   _delay_us(SERIAL_DELAY); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static void serial_delay_half1(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_delay_half1(void) { |  | ||||||
|   _delay_us(SERIAL_DELAY_HALF1); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static void serial_delay_half2(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_delay_half2(void) { |  | ||||||
|   _delay_us(SERIAL_DELAY_HALF2); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static void serial_output(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_output(void) { |  | ||||||
|   SERIAL_PIN_DDR |= SERIAL_PIN_MASK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // make the serial pin an input with pull-up resistor
 |  | ||||||
| inline static void serial_input_with_pullup(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_input_with_pullup(void) { |  | ||||||
|   SERIAL_PIN_DDR  &= ~SERIAL_PIN_MASK; |  | ||||||
|   SERIAL_PIN_PORT |= SERIAL_PIN_MASK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static uint8_t serial_read_pin(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| uint8_t serial_read_pin(void) { |  | ||||||
|   return !!(SERIAL_PIN_INPUT & SERIAL_PIN_MASK); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static void serial_low(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_low(void) { |  | ||||||
|   SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static void serial_high(void) ALWAYS_INLINE; |  | ||||||
| inline static |  | ||||||
| void serial_high(void) { |  | ||||||
|   SERIAL_PIN_PORT |= SERIAL_PIN_MASK; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) |  | ||||||
| { |  | ||||||
|     Transaction_table = sstd_table; |  | ||||||
|     Transaction_table_size = (uint8_t)sstd_table_size; |  | ||||||
|     serial_output(); |  | ||||||
|     serial_high(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) |  | ||||||
| { |  | ||||||
|     Transaction_table = sstd_table; |  | ||||||
|     Transaction_table_size = (uint8_t)sstd_table_size; |  | ||||||
|     serial_input_with_pullup(); |  | ||||||
| 
 |  | ||||||
|     // Enable INT0-INT3,INT6
 |  | ||||||
|     EIMSK |= EIMSK_BIT; |  | ||||||
| #if SERIAL_PIN_MASK == _BV(PE6) |  | ||||||
|     // Trigger on falling edge of INT6
 |  | ||||||
|     EICRB &= EICRx_BIT; |  | ||||||
| #else |  | ||||||
|     // Trigger on falling edge of INT0-INT3
 |  | ||||||
|     EICRA &= EICRx_BIT; |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Used by the sender to synchronize timing with the reciver.
 |  | ||||||
| static void sync_recv(void) NO_INLINE; |  | ||||||
| static |  | ||||||
| void sync_recv(void) { |  | ||||||
|   for (uint8_t i = 0; i < SERIAL_DELAY*5 && serial_read_pin(); i++ ) { |  | ||||||
|   } |  | ||||||
|   // This shouldn't hang if the target disconnects because the
 |  | ||||||
|   // serial line will float to high if the target does disconnect.
 |  | ||||||
|   while (!serial_read_pin()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Used by the reciver to send a synchronization signal to the sender.
 |  | ||||||
| static void sync_send(void) NO_INLINE; |  | ||||||
| static |  | ||||||
| void sync_send(void) { |  | ||||||
|   serial_low(); |  | ||||||
|   serial_delay(); |  | ||||||
|   serial_high(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Reads a byte from the serial line
 |  | ||||||
| static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) NO_INLINE; |  | ||||||
| static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) { |  | ||||||
|     uint8_t byte, i, p, pb; |  | ||||||
| 
 |  | ||||||
|   _delay_sub_us(READ_WRITE_START_ADJUST); |  | ||||||
|   for( i = 0, byte = 0, p = PARITY; i < bit; i++ ) { |  | ||||||
|       serial_delay_half1();   // read the middle of pulses
 |  | ||||||
|       if( serial_read_pin() ) { |  | ||||||
|           byte = (byte << 1) | 1; p ^= 1; |  | ||||||
|       } else { |  | ||||||
|           byte = (byte << 1) | 0; p ^= 0; |  | ||||||
|       } |  | ||||||
|       _delay_sub_us(READ_WRITE_WIDTH_ADJUST); |  | ||||||
|       serial_delay_half2(); |  | ||||||
|   } |  | ||||||
|   /* recive parity bit */ |  | ||||||
|   serial_delay_half1();   // read the middle of pulses
 |  | ||||||
|   pb = serial_read_pin(); |  | ||||||
|   _delay_sub_us(READ_WRITE_WIDTH_ADJUST); |  | ||||||
|   serial_delay_half2(); |  | ||||||
| 
 |  | ||||||
|   *pterrcount += (p != pb)? 1 : 0; |  | ||||||
| 
 |  | ||||||
|   return byte; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Sends a byte with MSB ordering
 |  | ||||||
| void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE; |  | ||||||
| void serial_write_chunk(uint8_t data, uint8_t bit) { |  | ||||||
|     uint8_t b, p; |  | ||||||
|     for( p = PARITY, b = 1<<(bit-1); b ; b >>= 1) { |  | ||||||
|         if(data & b) { |  | ||||||
|             serial_high(); p ^= 1; |  | ||||||
|         } else { |  | ||||||
|             serial_low();  p ^= 0; |  | ||||||
|         } |  | ||||||
|         serial_delay(); |  | ||||||
|     } |  | ||||||
|     /* send parity bit */ |  | ||||||
|     if(p & 1) { serial_high(); } |  | ||||||
|     else      { serial_low(); } |  | ||||||
|     serial_delay(); |  | ||||||
| 
 |  | ||||||
|     serial_low(); // sync_send() / senc_recv() need raise edge
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE; |  | ||||||
| static |  | ||||||
| void serial_send_packet(uint8_t *buffer, uint8_t size) { |  | ||||||
|   for (uint8_t i = 0; i < size; ++i) { |  | ||||||
|     uint8_t data; |  | ||||||
|     data = buffer[i]; |  | ||||||
|     sync_send(); |  | ||||||
|     serial_write_chunk(data,8); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE; |  | ||||||
| static |  | ||||||
| uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) { |  | ||||||
|   uint8_t pecount = 0; |  | ||||||
|   for (uint8_t i = 0; i < size; ++i) { |  | ||||||
|     uint8_t data; |  | ||||||
|     sync_recv(); |  | ||||||
|     data = serial_read_chunk(&pecount, 8); |  | ||||||
|     buffer[i] = data; |  | ||||||
|   } |  | ||||||
|   return pecount == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static |  | ||||||
| void change_sender2reciver(void) { |  | ||||||
|     sync_send();          //0
 |  | ||||||
|     serial_delay_half1(); //1
 |  | ||||||
|     serial_low();         //2
 |  | ||||||
|     serial_input_with_pullup(); //2
 |  | ||||||
|     serial_delay_half1(); //3
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline static |  | ||||||
| void change_reciver2sender(void) { |  | ||||||
|     sync_recv();     //0
 |  | ||||||
|     serial_delay();  //1
 |  | ||||||
|     serial_low();    //3
 |  | ||||||
|     serial_output(); //3
 |  | ||||||
|     serial_delay_half1(); //4
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline uint8_t nibble_bits_count(uint8_t bits) |  | ||||||
| { |  | ||||||
|     bits = (bits & 0x5) + (bits >> 1 & 0x5); |  | ||||||
|     bits = (bits & 0x3) + (bits >> 2 & 0x3); |  | ||||||
|     return bits; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // interrupt handle to be used by the target device
 |  | ||||||
| ISR(SERIAL_PIN_INTERRUPT) { |  | ||||||
| 
 |  | ||||||
| #ifndef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|   serial_low(); |  | ||||||
|   serial_output(); |  | ||||||
|   SSTD_t *trans = Transaction_table; |  | ||||||
| #else |  | ||||||
|   // recive transaction table index
 |  | ||||||
|   uint8_t tid, bits; |  | ||||||
|   uint8_t pecount = 0; |  | ||||||
|   sync_recv(); |  | ||||||
|   bits = serial_read_chunk(&pecount,7); |  | ||||||
|   tid = bits>>3; |  | ||||||
|   bits = (bits&7) != nibble_bits_count(tid); |  | ||||||
|   if( bits || pecount> 0 || tid > Transaction_table_size ) { |  | ||||||
|       return; |  | ||||||
|   } |  | ||||||
|   serial_delay_half1(); |  | ||||||
| 
 |  | ||||||
|   serial_high(); // response step1 low->high
 |  | ||||||
|   serial_output(); |  | ||||||
|   _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT*SLAVE_INT_ACK_WIDTH); |  | ||||||
|   SSTD_t *trans = &Transaction_table[tid]; |  | ||||||
|   serial_low(); // response step2 ack high->low
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|   // target send phase
 |  | ||||||
|   if( trans->target2initiator_buffer_size > 0 ) |  | ||||||
|       serial_send_packet((uint8_t *)trans->target2initiator_buffer, |  | ||||||
|                          trans->target2initiator_buffer_size); |  | ||||||
|   // target switch to input
 |  | ||||||
|   change_sender2reciver(); |  | ||||||
| 
 |  | ||||||
|   // target recive phase
 |  | ||||||
|   if( trans->initiator2target_buffer_size > 0 ) { |  | ||||||
|       if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer, |  | ||||||
|                                trans->initiator2target_buffer_size) ) { |  | ||||||
|           *trans->status = TRANSACTION_ACCEPTED; |  | ||||||
|       } else { |  | ||||||
|           *trans->status = TRANSACTION_DATA_ERROR; |  | ||||||
|       } |  | ||||||
|   } else { |  | ||||||
|       *trans->status = TRANSACTION_ACCEPTED; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   sync_recv(); //weit initiator output to high
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /////////
 |  | ||||||
| //  start transaction by initiator
 |  | ||||||
| //
 |  | ||||||
| // int  soft_serial_transaction(int sstd_index)
 |  | ||||||
| //
 |  | ||||||
| // Returns:
 |  | ||||||
| //    TRANSACTION_END
 |  | ||||||
| //    TRANSACTION_NO_RESPONSE
 |  | ||||||
| //    TRANSACTION_DATA_ERROR
 |  | ||||||
| // this code is very time dependent, so we need to disable interrupts
 |  | ||||||
| #ifndef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
| int  soft_serial_transaction(void) { |  | ||||||
|   SSTD_t *trans = Transaction_table; |  | ||||||
| #else |  | ||||||
| int  soft_serial_transaction(int sstd_index) { |  | ||||||
|   if( sstd_index > Transaction_table_size ) |  | ||||||
|       return TRANSACTION_TYPE_ERROR; |  | ||||||
|   SSTD_t *trans = &Transaction_table[sstd_index]; |  | ||||||
| #endif |  | ||||||
|   cli(); |  | ||||||
| 
 |  | ||||||
|   // signal to the target that we want to start a transaction
 |  | ||||||
|   serial_output(); |  | ||||||
|   serial_low(); |  | ||||||
|   _delay_us(SLAVE_INT_WIDTH_US); |  | ||||||
| 
 |  | ||||||
| #ifndef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
|   // wait for the target response
 |  | ||||||
|   serial_input_with_pullup(); |  | ||||||
|   _delay_us(SLAVE_INT_RESPONSE_TIME); |  | ||||||
| 
 |  | ||||||
|   // check if the target is present
 |  | ||||||
|   if (serial_read_pin()) { |  | ||||||
|     // target failed to pull the line low, assume not present
 |  | ||||||
|     serial_output(); |  | ||||||
|     serial_high(); |  | ||||||
|     *trans->status = TRANSACTION_NO_RESPONSE; |  | ||||||
|     sei(); |  | ||||||
|     return TRANSACTION_NO_RESPONSE; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| #else |  | ||||||
|   // send transaction table index
 |  | ||||||
|   int tid = (sstd_index<<3) | (7 & nibble_bits_count(sstd_index)); |  | ||||||
|   sync_send(); |  | ||||||
|   _delay_sub_us(TID_SEND_ADJUST); |  | ||||||
|   serial_write_chunk(tid, 7); |  | ||||||
|   serial_delay_half1(); |  | ||||||
| 
 |  | ||||||
|   // wait for the target response (step1 low->high)
 |  | ||||||
|   serial_input_with_pullup(); |  | ||||||
|   while( !serial_read_pin() ) { |  | ||||||
|       _delay_sub_us(2); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // check if the target is present (step2 high->low)
 |  | ||||||
|   for( int i = 0; serial_read_pin(); i++ ) { |  | ||||||
|       if (i > SLAVE_INT_ACK_WIDTH + 1) { |  | ||||||
|           // slave failed to pull the line low, assume not present
 |  | ||||||
|           serial_output(); |  | ||||||
|           serial_high(); |  | ||||||
|           *trans->status = TRANSACTION_NO_RESPONSE; |  | ||||||
|           sei(); |  | ||||||
|           return TRANSACTION_NO_RESPONSE; |  | ||||||
|       } |  | ||||||
|       _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT); |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|   // initiator recive phase
 |  | ||||||
|   // if the target is present syncronize with it
 |  | ||||||
|   if( trans->target2initiator_buffer_size > 0 ) { |  | ||||||
|       if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, |  | ||||||
|                                 trans->target2initiator_buffer_size) ) { |  | ||||||
|           serial_output(); |  | ||||||
|           serial_high(); |  | ||||||
|           *trans->status = TRANSACTION_DATA_ERROR; |  | ||||||
|           sei(); |  | ||||||
|           return TRANSACTION_DATA_ERROR; |  | ||||||
|       } |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|   // initiator switch to output
 |  | ||||||
|   change_reciver2sender(); |  | ||||||
| 
 |  | ||||||
|   // initiator send phase
 |  | ||||||
|   if( trans->initiator2target_buffer_size > 0 ) { |  | ||||||
|       serial_send_packet((uint8_t *)trans->initiator2target_buffer, |  | ||||||
|                          trans->initiator2target_buffer_size); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // always, release the line when not in use
 |  | ||||||
|   sync_send(); |  | ||||||
| 
 |  | ||||||
|   *trans->status = TRANSACTION_END; |  | ||||||
|   sei(); |  | ||||||
|   return TRANSACTION_END; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef SERIAL_USE_MULTI_TRANSACTION |  | ||||||
| int soft_serial_get_and_clean_status(int sstd_index) { |  | ||||||
|     SSTD_t *trans = &Transaction_table[sstd_index]; |  | ||||||
|     cli(); |  | ||||||
|     int retval = *trans->status; |  | ||||||
|     *trans->status = 0;; |  | ||||||
|     sei(); |  | ||||||
|     return retval; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| // Helix serial.c history
 |  | ||||||
| //   2018-1-29 fork from let's split and add PD2, modify sync_recv() (#2308, bceffdefc)
 |  | ||||||
| //   2018-6-28 bug fix master to slave comm and speed up (#3255, 1038bbef4)
 |  | ||||||
| //             (adjusted with avr-gcc 4.9.2)
 |  | ||||||
| //   2018-7-13 remove USE_SERIAL_PD2 macro (#3374, f30d6dd78)
 |  | ||||||
| //             (adjusted with avr-gcc 4.9.2)
 |  | ||||||
| //   2018-8-11 add support multi-type transaction (#3608, feb5e4aae)
 |  | ||||||
| //             (adjusted with avr-gcc 4.9.2)
 |  | ||||||
| //   2018-10-21 fix serial and RGB animation conflict (#4191, 4665e4fff)
 |  | ||||||
| //             (adjusted with avr-gcc 7.3.0)
 |  | ||||||
| //   2018-10-28 re-adjust compiler depend value of delay (#4269, 8517f8a66)
 |  | ||||||
| //             (adjusted with avr-gcc 5.4.0, 7.3.0)
 |  | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nick Brassel
						Nick Brassel