cc3200: Implement support for os.dupterm().

pull/1480/merge
Daniel Campora 2015-09-25 15:20:07 +02:00
rodzic a7261ae059
commit ef369249cb
14 zmienionych plików z 102 dodań i 126 usunięć

Wyświetl plik

@ -36,6 +36,7 @@
#include "inc/hw_nvic.h" #include "inc/hw_nvic.h"
#include "hw_memmap.h" #include "hw_memmap.h"
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/runtime.h"
#include MICROPY_HAL_H #include MICROPY_HAL_H
#include "rom_map.h" #include "rom_map.h"
#include "interrupt.h" #include "interrupt.h"
@ -47,6 +48,7 @@
#include "pybuart.h" #include "pybuart.h"
#include "utils.h" #include "utils.h"
#include "irq.h" #include "irq.h"
#include "moduos.h"
#ifdef USE_FREERTOS #ifdef USE_FREERTOS
#include "FreeRTOS.h" #include "FreeRTOS.h"
@ -67,11 +69,6 @@ static void hal_TickInit (void);
******************************************************************************/ ******************************************************************************/
static volatile uint32_t HAL_tickCount; static volatile uint32_t HAL_tickCount;
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
struct _pyb_uart_obj_t *pyb_stdio_uart;
/****************************************************************************** /******************************************************************************
DECLARE IMPORTED DATA DECLARE IMPORTED DATA
******************************************************************************/ ******************************************************************************/
@ -141,34 +138,56 @@ void mp_hal_stdout_tx_str(const char *str) {
} }
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
// send stdout to UART if (MP_STATE_PORT(os_term_dup_obj)) {
if (pyb_stdio_uart != NULL) { if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
uart_tx_strn(pyb_stdio_uart, str, len); uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len);
} else {
MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_bytes((const byte*)str, len);
mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write);
}
} }
// and also to telnet // and also to telnet
if (telnet_is_active()) { telnet_tx_strn(str, len);
telnet_tx_strn(str, len);
}
} }
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { void mp_hal_stdout_tx_strn_cooked (const char *str, uint32_t len) {
// send stdout to UART int32_t nslen = 0;
if (pyb_stdio_uart != NULL) { const char *_str = str;
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
for (int i = 0; i < len; i++) {
if (str[i] == '\n') {
mp_hal_stdout_tx_strn(_str, nslen);
mp_hal_stdout_tx_strn("\r\n", 2);
_str += nslen + 1;
nslen = 0;
} else {
nslen++;
}
} }
// and also to telnet if (_str < str + len) {
if (telnet_is_active()) { mp_hal_stdout_tx_strn(_str, nslen);
telnet_tx_strn_cooked(str, len);
} }
} }
int mp_hal_stdin_rx_chr(void) { int mp_hal_stdin_rx_chr(void) {
for ( ;; ) { for ( ;; ) {
// read telnet first
if (telnet_rx_any()) { if (telnet_rx_any()) {
return telnet_rx_char(); return telnet_rx_char();
} } else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup
else if (pyb_stdio_uart != NULL && uart_rx_any(pyb_stdio_uart)) { if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
return uart_rx_char(pyb_stdio_uart); if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) {
return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o);
}
} else {
MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1);
mp_obj_t rbytes = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read);
if (rbytes != mp_const_none) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(rbytes, &bufinfo, MP_BUFFER_READ);
return ((int *)(bufinfo.buf))[0];
}
}
} }
HAL_Delay(1); HAL_Delay(1);
} }

Wyświetl plik

@ -55,11 +55,6 @@
" isb \n"); \ " isb \n"); \
} }
/******************************************************************************
DECLARE PUBLIC DATA
******************************************************************************/
extern struct _pyb_uart_obj_t *pyb_stdio_uart;
/****************************************************************************** /******************************************************************************
DECLARE PUBLIC FUNCTIONS DECLARE PUBLIC FUNCTIONS
******************************************************************************/ ******************************************************************************/

Wyświetl plik

@ -141,28 +141,6 @@ STATIC mp_obj_t pyb_unique_id(void) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id); STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
/// \function repl_uart(uart)
/// Get or set the UART object that the REPL is repeated on.
STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {
if (n_args == 0) {
if (pyb_stdio_uart == NULL) {
return mp_const_none;
} else {
return pyb_stdio_uart;
}
} else {
if (args[0] == mp_const_none) {
pyb_stdio_uart = NULL;
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
pyb_stdio_uart = args[0];
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
}
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart);
MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
STATIC const mp_map_elem_t pyb_module_globals_table[] = { STATIC const mp_map_elem_t pyb_module_globals_table[] = {
@ -174,7 +152,6 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
#endif #endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },

Wyświetl plik

@ -34,7 +34,7 @@
#include "py/objstr.h" #include "py/objstr.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "genhdr/mpversion.h" #include "genhdr/mpversion.h"
#include "ff.h" #include "moduos.h"
#include "diskio.h" #include "diskio.h"
#include "sflash_diskio.h" #include "sflash_diskio.h"
#include "file.h" #include "file.h"
@ -42,8 +42,8 @@
#include "mpexception.h" #include "mpexception.h"
#include "version.h" #include "version.h"
#include "timeutils.h" #include "timeutils.h"
#include "moduos.h"
#include "pybsd.h" #include "pybsd.h"
#include "pybuart.h"
/// \module os - basic "operating system" services /// \module os - basic "operating system" services
/// ///
@ -60,6 +60,7 @@
DECLARE PRIVATE DATA DECLARE PRIVATE DATA
******************************************************************************/ ******************************************************************************/
STATIC uint32_t os_num_mounted_devices; STATIC uint32_t os_num_mounted_devices;
STATIC os_term_dup_obj_t os_term_dup_obj;
/****************************************************************************** /******************************************************************************
DEFINE PUBLIC FUNCTIONS DEFINE PUBLIC FUNCTIONS
@ -536,6 +537,31 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs); STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs);
STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
if (n_args == 0) {
if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
return mp_const_none;
} else {
return MP_STATE_PORT(os_term_dup_obj)->stream_o;
}
} else {
mp_obj_t stream_o = args[0];
if (stream_o == mp_const_none) {
MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
} else {
if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) {
// must be a stream-like object providing at least read and write methods
mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
}
os_term_dup_obj.stream_o = stream_o;
MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
}
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
STATIC const mp_map_elem_t os_module_globals_table[] = { STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) }, { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
@ -554,6 +580,7 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dupterm), (mp_obj_t)&os_dupterm_obj },
/// \constant sep - separation character used in paths /// \constant sep - separation character used in paths
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) }, { MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },

Wyświetl plik

@ -28,6 +28,11 @@
#ifndef MODUOS_H_ #ifndef MODUOS_H_
#define MODUOS_H_ #define MODUOS_H_
#include "ff.h"
/******************************************************************************
DEFINE PUBLIC TYPES
******************************************************************************/
typedef struct _os_fs_mount_t { typedef struct _os_fs_mount_t {
mp_obj_t device; mp_obj_t device;
const char *path; const char *path;
@ -40,6 +45,15 @@ typedef struct _os_fs_mount_t {
uint8_t vol; uint8_t vol;
} os_fs_mount_t; } os_fs_mount_t;
typedef struct _os_term_dup_obj_t {
mp_obj_t stream_o;
mp_obj_t read[3];
mp_obj_t write[3];
} os_term_dup_obj_t;
/******************************************************************************
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
void moduos_init0 (void); void moduos_init0 (void);
os_fs_mount_t *osmount_find_by_path (const char *path); os_fs_mount_t *osmount_find_by_path (const char *path);
os_fs_mount_t *osmount_find_by_volume (uint8_t vol); os_fs_mount_t *osmount_find_by_volume (uint8_t vol);

Wyświetl plik

@ -55,6 +55,7 @@
#include "pin.h" #include "pin.h"
#include "pybpin.h" #include "pybpin.h"
#include "pins.h" #include "pins.h"
#include "moduos.h"
/// \moduleref pyb /// \moduleref pyb
/// \class UART - duplex serial communication bus /// \class UART - duplex serial communication bus
@ -168,15 +169,6 @@ bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) {
return true; return true;
} }
void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) {
for (const char *top = str + len; str < top; str++) {
if (*str == '\n') {
uart_tx_char(self, '\r');
}
uart_tx_char(self, *str);
}
}
/****************************************************************************** /******************************************************************************
DEFINE PRIVATE FUNCTIONS DEFINE PRIVATE FUNCTIONS
******************************************************************************/ ******************************************************************************/
@ -261,12 +253,10 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT); MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
while (UARTCharsAvail(self->reg)) { while (UARTCharsAvail(self->reg)) {
int data = MAP_UARTCharGetNonBlocking(self->reg); int data = MAP_UARTCharGetNonBlocking(self->reg);
if (pyb_stdio_uart == self && data == user_interrupt_char) { if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == user_interrupt_char) {
// raise an exception when interrupts are finished // raise an exception when interrupts are finished
mpexception_keyboard_nlr_jump(); mpexception_keyboard_nlr_jump();
} } else { // there's always a read buffer available
// there's always a read buffer available
else {
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN; uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
if (next_head != self->read_buf_tail) { if (next_head != self->read_buf_tail) {
// only store data if room in buf // only store data if room in buf

Wyświetl plik

@ -42,6 +42,5 @@ uint32_t uart_rx_any(pyb_uart_obj_t *uart_obj);
int uart_rx_char(pyb_uart_obj_t *uart_obj); int uart_rx_char(pyb_uart_obj_t *uart_obj);
bool uart_tx_char(pyb_uart_obj_t *self, int c); bool uart_tx_char(pyb_uart_obj_t *self, int c);
bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
#endif // PYBUART_H_ #endif // PYBUART_H_

Wyświetl plik

@ -160,10 +160,11 @@ extern const struct _mp_obj_module_t mp_module_ussl;
mp_obj_t mp_const_user_interrupt; \ mp_obj_t mp_const_user_interrupt; \
mp_obj_t pyb_config_main; \ mp_obj_t pyb_config_main; \
mp_obj_list_t pybsleep_obj_list; \ mp_obj_list_t pybsleep_obj_list; \
mp_obj_list_t mp_irq_obj_list; \ mp_obj_list_t mp_irq_obj_list; \
mp_obj_list_t pyb_timer_channel_obj_list; \ mp_obj_list_t pyb_timer_channel_obj_list; \
mp_obj_list_t mount_obj_list; \ mp_obj_list_t mount_obj_list; \
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \ struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
struct _os_term_dup_obj_t *os_term_dup_obj; \
// type definitions for the specific machine // type definitions for the specific machine

Wyświetl plik

@ -138,17 +138,6 @@ soft_reset:
moduos_init0(); moduos_init0();
rng_init0(); rng_init0();
#ifdef LAUNCHXL
// instantiate the stdio uart on the default pins
mp_obj_t args[2] = {
mp_obj_new_int(MICROPY_STDIO_UART),
mp_obj_new_int(MICROPY_STDIO_UART_BAUD),
};
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
#else
pyb_stdio_uart = MP_OBJ_NULL;
#endif
pybsleep_reset_cause_t rstcause = pybsleep_get_reset_cause(); pybsleep_reset_cause_t rstcause = pybsleep_get_reset_cause();
if (rstcause < PYB_SLP_SOFT_RESET) { if (rstcause < PYB_SLP_SOFT_RESET) {
if (rstcause == PYB_SLP_HIB_RESET) { if (rstcause == PYB_SLP_HIB_RESET) {

Wyświetl plik

@ -25,25 +25,21 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
// qstrs specific to this port // for pyb module
Q(__name__)
Q(help)
Q(pyb) Q(pyb)
Q(help)
#ifdef DEBUG
Q(info) Q(info)
#endif
Q(reset) Q(reset)
Q(main) Q(main)
Q(sync) Q(sync)
Q(gc)
Q(rng) Q(rng)
Q(toggle)
Q(write)
Q(input)
Q(freq) Q(freq)
Q(unique_id) Q(unique_id)
Q(disable_irq) Q(disable_irq)
Q(enable_irq) Q(enable_irq)
Q(flush)
Q(repl_uart)
// entries for sys.path // entries for sys.path
Q(/flash) Q(/flash)
Q(/flash/lib) Q(/flash/lib)
@ -81,6 +77,7 @@ Q(urandom)
Q(mkfs) Q(mkfs)
Q(mount) Q(mount)
Q(unmount) Q(unmount)
Q(dupterm)
Q(readonly) Q(readonly)
Q(readblocks) Q(readblocks)
Q(writeblocks) Q(writeblocks)
@ -90,6 +87,8 @@ Q(count)
// for file class // for file class
Q(seek) Q(seek)
Q(tell) Q(tell)
Q(input)
Q(flush)
// for Pin class // for Pin class
Q(Pin) Q(Pin)
@ -348,7 +347,6 @@ Q(read)
Q(readinto) Q(readinto)
Q(write_readinto) Q(write_readinto)
Q(nbytes) Q(nbytes)
Q(write)
Q(buf) Q(buf)
Q(MASTER) Q(MASTER)
Q(MSB) Q(MSB)

Wyświetl plik

@ -244,34 +244,14 @@ void telnet_run (void) {
} }
void telnet_tx_strn (const char *str, int len) { void telnet_tx_strn (const char *str, int len) {
if (len > 0 && telnet_data.n_sd > 0) { if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
telnet_send_with_retries(telnet_data.n_sd, str, len); telnet_send_with_retries(telnet_data.n_sd, str, len);
} }
} }
void telnet_tx_strn_cooked (const char *str, uint len) {
int32_t nslen = 0;
const char *_str = str;
for (int i = 0; i < len; i++) {
if (str[i] == '\n') {
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
telnet_send_with_retries(telnet_data.n_sd, "\r\n", 2);
_str += nslen + 1;
nslen = 0;
}
else {
nslen++;
}
}
if (_str < str + len) {
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
}
}
bool telnet_rx_any (void) { bool telnet_rx_any (void) {
return (telnet_data.n_sd > 0) ? ((telnet_data.rxRindex != telnet_data.rxWindex) && return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
(telnet_data.state == E_TELNET_STE_LOGGED_IN)) : false; telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
} }
int telnet_rx_char (void) { int telnet_rx_char (void) {
@ -300,14 +280,6 @@ void telnet_reset (void) {
telnet_data.state = E_TELNET_STE_START; telnet_data.state = E_TELNET_STE_START;
} }
bool telnet_is_enabled (void) {
return telnet_data.enabled;
}
bool telnet_is_active (void) {
return (telnet_data.state == E_TELNET_STE_LOGGED_IN);
}
/****************************************************************************** /******************************************************************************
DEFINE PRIVATE FUNCTIONS DEFINE PRIVATE FUNCTIONS
******************************************************************************/ ******************************************************************************/

Wyświetl plik

@ -33,13 +33,10 @@
extern void telnet_init (void); extern void telnet_init (void);
extern void telnet_run (void); extern void telnet_run (void);
extern void telnet_tx_strn (const char *str, int len); extern void telnet_tx_strn (const char *str, int len);
extern void telnet_tx_strn_cooked (const char *str, uint len);
extern bool telnet_rx_any (void); extern bool telnet_rx_any (void);
extern int telnet_rx_char (void); extern int telnet_rx_char (void);
extern void telnet_enable (void); extern void telnet_enable (void);
extern void telnet_disable (void); extern void telnet_disable (void);
extern void telnet_reset (void); extern void telnet_reset (void);
extern bool telnet_is_enabled (void);
extern bool telnet_is_active (void);
#endif /* TELNET_H_ */ #endif /* TELNET_H_ */

Wyświetl plik

@ -6,7 +6,6 @@ UART0 and UART1 must be connected together for this test to pass.
from pyb import UART from pyb import UART
from pyb import Pin from pyb import Pin
import os import os
import pyb
import time import time
machine = os.uname().machine machine = os.uname().machine
@ -19,8 +18,8 @@ elif 'WiPy' in machine:
else: else:
raise Exception('Board not supported!') raise Exception('Board not supported!')
# just in case we have stdio duplicated on any of the uarts # just in case we have the repl duplicated on any of the uarts
pyb.repl_uart(None) os.dupterm(None)
for uart_id in uart_id_range: for uart_id in uart_id_range:
uart = UART(uart_id, 38400) uart = UART(uart_id, 38400)

Wyświetl plik

@ -4,7 +4,6 @@ UART IRQ test for the CC3200 based boards.
from pyb import UART from pyb import UART
import os import os
import pyb
import time import time
machine = os.uname().machine machine = os.uname().machine
@ -16,7 +15,7 @@ else:
raise Exception('Board not supported!') raise Exception('Board not supported!')
# just in case we have stdio duplicated on any of the uarts # just in case we have stdio duplicated on any of the uarts
pyb.repl_uart(None) os.dupterm(None)
uart0 = UART(0, 1000000, pins=uart_pins[0][0]) uart0 = UART(0, 1000000, pins=uart_pins[0][0])
uart1 = UART(1, 1000000, pins=uart_pins[1][0]) uart1 = UART(1, 1000000, pins=uart_pins[1][0])