//-------------------------------------------------------------------------- // Reset all of the devices on the 1-Wire Net and return the result. // // 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to // indicate the symbolic port number. // // Returns: TRUE(1): presence pulse(s) detected, device(s) reset // FALSE(0): no presence pulses detected // SMALLINT owTouchReset(int portnum) { int reg; int ovd = (sockit_owm.ovd >> portnum) & 0x1; // lock transfer ALT_SEM_PEND (sockit_owm.trn, 0); // write RST IOWR_SOCKIT_OWM (sockit_owm.base, (sockit_owm.pwr << SOCKIT_OWM_POWER_OFST) | (portnum << SOCKIT_OWM_SEL_OFST) | (sockit_owm.ena << SOCKIT_OWM_ETX_OFST) | (ovd << SOCKIT_OWM_OVD_OFST) | SOCKIT_OWM_RST_MSK); // wait for irq to set the transfer end flag ALT_FLAG_PEND (sockit_owm.irq, 0x1, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); // wait for STX (end of transfer cycle) and read the presence status while ((reg = IORD_SOCKIT_OWM (sockit_owm.base)) & SOCKIT_OWM_TRN_MSK); // release transfer lock ALT_SEM_POST (sockit_owm.trn); // return DRX (presence detect) return (~reg >> SOCKIT_OWM_DAT_OFST) & 0x1; }
//-------------------------------------------------------------------------- // Description: // Delay for at least 'len' ms // void msDelay(int len) { #if SOCKIT_OWM_HW_DLY int i; // lock transfer ALT_SEM_PEND (sockit_owm.trn, 0); for (i=0; i<len; i++) { // create a 960us pause IOWR_SOCKIT_OWM (sockit_owm.base, ( sockit_owm.pwr << SOCKIT_OWM_POWER_OFST) | ( sockit_owm.ena << SOCKIT_OWM_ETX_OFST) | ((sockit_owm.pwr & 0x1) << SOCKIT_OWM_PWR_OFST) | SOCKIT_OWM_DLY_MSK); // wait for irq to set the transfer end flag ALT_FLAG_PEND (sockit_owm.irq, 0x1, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); // wait for STX (end of transfer cycle) while (IORD_SOCKIT_OWM (sockit_owm.base) & SOCKIT_OWM_TRN_MSK); // release transfer lock ALT_SEM_POST (sockit_owm.trn); } #else #ifdef UCOS_II // uCOS-II timed delay OSTimeDlyHMSM(0,0,0,len); #else // Altera HAL us delay usleep (1000*len); #endif #endif }
void task1(void* pdata) { ALT_SEM_PEND(display,0); OSTimeDly(1); volatile short * pixel_ctrl_ptr = (volatile short *) pdata; int i=0; //d-pad drawrectangle( pixel_ctrl_ptr , 80, 100, 10, 15, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 80, 130, 10, 15, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 62, 117, 15, 10, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 93, 117, 15, 10, 0xFFFF); //select start drawrectangle( pixel_ctrl_ptr , 130, 117,15, 10, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 160, 117, 15, 10, 0xFFFF); //buttons drawcircle( pixel_ctrl_ptr ,205,121,7,0xFFFF); drawcircle( pixel_ctrl_ptr ,235,121,7,0xFFFF); drawcircle( pixel_ctrl_ptr ,220,106,7,0xFFFF); drawcircle( pixel_ctrl_ptr ,220,136,7,0xFFFF); //upper keys drawrectangle( pixel_ctrl_ptr , 75, 80, 20, 10, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 75, 65, 20, 10, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 210, 80, 20,10, 0xFFFF); drawrectangle( pixel_ctrl_ptr , 210, 65, 20, 10, 0xFFFF); //analog sticks drawcircle( pixel_ctrl_ptr ,110,155,15,0xFFFF); drawcircle( pixel_ctrl_ptr ,195,155,15,0xFFFF); drawcircle( pixel_ctrl_ptr ,110,155,9,0xFFFF); drawcircle( pixel_ctrl_ptr ,195,155,9,0xFFFF); while(1) { if(i>=10) { drawline(pixel_ctrl_ptr,0+i-10,50,0+i-10,60,0x0000); drawline(pixel_ctrl_ptr,0+i-11,50,0+i-11,60,0x0000); } if(i<=320) { drawline(pixel_ctrl_ptr,0+i,50,0+i,60,0x0FFF); drawline(pixel_ctrl_ptr,0+i+1,50,0+i+1,60,0x0FFF); } if(i==330) { i = 0; } i++; wait_for_vsync(buffer_register,dma_control); OSTimeDly(1); ALT_SEM_POST(display); } }
/* * altera_avalon_mutex_lock - Lock the hardware mutex * */ void altera_avalon_mutex_lock( alt_mutex_dev* dev, alt_u32 value ) { /* * When running in a multi threaded environment, obtain the "lock" * semaphore. This ensures that reading from the device is thread-safe. */ ALT_SEM_PEND (dev->lock, 0); while ( alt_mutex_trylock( dev, value ) != 0); }
int alt_get_fd (alt_dev* dev) { alt_32 i; int rc = -EMFILE; /* * Take the alt_fd_list_lock semaphore in order to avoid races when * accessing the file descriptor pool. */ ALT_SEM_PEND(alt_fd_list_lock, 0); /* * Search through the list of file descriptors, and allocate the first * free descriptor that's found. * * If a free descriptor is found, then the value of "alt_max_fd" is * updated accordingly. "alt_max_fd" is a 'highwater mark' which * indicates the highest file descriptor ever allocated. This is used to * improve efficency when searching the file descriptor list, and * therefore reduce contention on the alt_fd_list_lock semaphore. */ for (i = 0; i < ALT_MAX_FD; i++) { if (!alt_fd_list[i].dev) { alt_fd_list[i].dev = dev; if (i > alt_max_fd) { alt_max_fd = i; } rc = i; goto alt_get_fd_exit; } } alt_get_fd_exit: /* * Release the alt_fd_list_lock semaphore now that we are done with the * file descriptor pool. */ ALT_SEM_POST(alt_fd_list_lock); return rc; }
/* * altera_avalon_mutex_trylock - Try to lock the hardware mutex * * returns 0 on success -1 otherwise * */ int altera_avalon_mutex_trylock( alt_mutex_dev* dev, alt_u32 value ) { int ret_code; ALT_SEM_PEND (dev->lock, 0); ret_code = alt_mutex_trylock( dev, value); /* * If the try failed then release the thread Mutex */ if (ret_code) { ALT_SEM_POST (dev->lock); } return ret_code; }
int alt_fd_lock (alt_fd* fd) { int i; int rc = 0; ALT_SEM_PEND(alt_fd_list_lock, 0); for (i = 0; i < alt_max_fd; i++) { if ((&alt_fd_list[i] != fd) && (alt_fd_list[i].dev == fd->dev)) { rc = -EACCES; goto alt_fd_lock_exit; } } fd->fd_flags |= ALT_FD_EXCL; alt_fd_lock_exit: ALT_SEM_POST(alt_fd_list_lock); return rc; }
//------------------------------------------------------------------------------- int alt_avn_jtag_uart_read(alt_avn_jtag_uart_state* sp, char * buffer, int space, int flags) { char * ptr = buffer; alt_irq_context context; unsigned int n; /* * When running in a multi threaded environment, obtain the "read_lock" * semaphore. This ensures that reading from the device is thread-safe. */ ALT_SEM_PEND (sp->read_lock, 0); while (space > 0) { unsigned int in, out; /* Read as much data as possible */ do { in = sp->rx_in; out = sp->rx_out; if (in >= out) n = in - out; else n = ALTERA_AVALON_JTAG_UART_BUF_LEN - out; if (n == 0) break; /* No more data available */ if (n > space) n = space; memcpy(ptr, sp->rx_buf + out, n); ptr += n; space -= n; sp->rx_out = (out + n) % ALTERA_AVALON_JTAG_UART_BUF_LEN; } while (space > 0); /* If we read any data then return it */ if (ptr != buffer) break; /* If in non-blocking mode then return error */ if (flags & O_NONBLOCK) break; /* OS Present: Pend on a flag if the OS is running, otherwise spin */ if(OSRunning == OS_TRUE) { /* * When running in a multi-threaded mode, we pend on the read event * flag set and timeout event flag set in the isr. This avoids wasting CPU * cycles waiting in this thread, when we could be doing something more * profitable elsewhere. */ ALT_FLAG_PEND (sp->events, ALT_JTAG_UART_READ_RDY | ALT_JTAG_UART_TIMEOUT, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); } else { /* Spin until more data arrives or until host disconnects */ while (in == sp->rx_in && sp->host_inactive < sp->timeout) ; } if (in == sp->rx_in) break; } /* * Now that access to the circular buffer is complete, release the read * semaphore so that other threads can access the buffer. */ ALT_SEM_POST (sp->read_lock); if (ptr != buffer) { /* If we read any data then there is space in the buffer so enable interrupts */ context = alt_irq_disable_all(); sp->irq_enable |= ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK; IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(sp->base, sp->irq_enable); alt_irq_enable_all(context); } if (ptr != buffer) return ptr - buffer; else if (flags & O_NONBLOCK) return -EWOULDBLOCK; else return -EIO; }
int alt_avn_jtag_uart_write(alt_avn_jtag_uart_state* sp, const char * ptr, int count, int flags) { /* Remove warning at optimisation level 03 by seting out to 0 */ unsigned int in, out=0; unsigned int n; alt_irq_context context; const char * start = ptr; /* * When running in a multi threaded environment, obtain the "write_lock" * semaphore. This ensures that writing to the device is thread-safe. */ ALT_SEM_PEND (sp->write_lock, 0); do { /* Copy as much as we can into the transmit buffer */ while (count > 0) { /* We need a stable value of the out pointer to calculate the space available */ in = sp->tx_in; out = sp->tx_out; if (in < out) n = out - 1 - in; else if (out > 0) n = ALTERA_AVALON_JTAG_UART_BUF_LEN - in; else n = ALTERA_AVALON_JTAG_UART_BUF_LEN - 1 - in; if (n == 0) break; if (n > count) n = count; memcpy(sp->tx_buf + in, ptr, n); ptr += n; count -= n; sp->tx_in = (in + n) % ALTERA_AVALON_JTAG_UART_BUF_LEN; } /* * If interrupts are disabled then we could transmit here, we only need * to enable interrupts if there is no space left in the FIFO * * For now kick the interrupt routine every time to make it transmit * the data */ context = alt_irq_disable_all(); sp->irq_enable |= ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK; IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(sp->base, sp->irq_enable); alt_irq_enable_all(context); /* * If there is any data left then either return now or block until * some has been sent */ /* consider: test whether there is anything there while doing this and delay for at most 2s. */ if (count > 0) { if (flags & O_NONBLOCK) break; /* OS Present: Pend on a flag if the OS is running, otherwise spin */ if(OSRunning == OS_TRUE) { /* * When running in a multi-threaded mode, we pend on the write event * flag set or the timeout flag in the isr. This avoids wasting CPU * cycles waiting in this thread, when we could be doing something * more profitable elsewhere. */ ALT_FLAG_PEND (sp->events, ALT_JTAG_UART_WRITE_RDY | ALT_JTAG_UART_TIMEOUT, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); } else { /* * OS not running: Wait for data to be removed from buffer. * Once the interrupt routine has removed some data then we * will be able to insert some more. */ while (out == sp->tx_out && sp->host_inactive < sp->timeout) ; } if (out == sp->tx_out) break; } } while (count > 0); /* * Now that access to the circular buffer is complete, release the write * semaphore so that other threads can access the buffer. */ ALT_SEM_POST (sp->write_lock); if (ptr != start) return ptr - start; else if (flags & O_NONBLOCK) return -EWOULDBLOCK; else return -EIO; /* Host not connected */ }
int alt_lcd_16207_write(alt_fd* fd, const char* ptr, int len) { alt_LCD_16207_dev * dev = (alt_LCD_16207_dev*) fd->dev; const char * end = ptr + len; int y; int widthmax; /* When running in a multi threaded environment, obtain the "write_lock" * semaphore. This ensures that writing to the device is thread-safe. */ ALT_SEM_PEND (dev->write_lock, 0); /* Tell the routine which is called off the timer interrupt that the * foreground routines are active so it must not repaint the display. */ dev->active = 1; for ( ; ptr < end ; ptr++) { char c = *ptr; if (dev->esccount >= 0) { unsigned int esccount = dev->esccount; /* Single character escape sequences can end with any character * Multi character escape sequences start with '[' and contain * digits and semicolons before terminating */ if ((esccount == 0 && c != '[') || (esccount > 0 && !isdigit(c) && c != ';')) { dev->escape[esccount] = 0; lcd_handle_escape(dev, c); dev->esccount = -1; } else if (dev->esccount < sizeof(dev->escape)-1) { dev->escape[esccount] = c; dev->esccount++; } } else if (c == 27) /* ESC */ { dev->esccount = 0; } else if (c == '\r') { dev->x = 0; } else if (c == '\n') { dev->x = 0; dev->y++; /* Let the cursor sit at X=0, Y=HEIGHT without scrolling so the user * can print two lines of data without losing one. */ if (dev->y > ALT_LCD_HEIGHT) lcd_scroll_up(dev); } else if (c == '\b') { if (dev->x > 0) dev->x--; } else if (isprint(c)) { /* If we didn't scroll on the last linefeed then we might need to do * it now. */ if (dev->y >= ALT_LCD_HEIGHT) lcd_scroll_up(dev); if (dev->x < ALT_LCD_VIRTUAL_WIDTH) dev->line[dev->y].data[dev->x] = c; dev->x++; } } /* Recalculate the scrolling parameters */ widthmax = ALT_LCD_WIDTH; for (y = 0 ; y < ALT_LCD_HEIGHT ; y++) { int width; for (width = ALT_LCD_VIRTUAL_WIDTH ; width > 0 ; width--) if (dev->line[y].data[width-1] != ' ') break; /* The minimum width is the size of the LCD panel. If the real width * is long enough to require scrolling then add an extra space so the * end of the message doesn't run into the beginning of it. */ if (width <= ALT_LCD_WIDTH) width = ALT_LCD_WIDTH; else width++; dev->line[y].width = width; if (widthmax < width) widthmax = width; dev->line[y].speed = 0; /* By default lines don't scroll */ } if (widthmax <= ALT_LCD_WIDTH) dev->scrollmax = 0; else { widthmax *= 2; dev->scrollmax = widthmax; /* Now calculate how fast each of the other lines should go */ for (y = 0 ; y < ALT_LCD_HEIGHT ; y++) if (dev->line[y].width > ALT_LCD_WIDTH) { /* You have three options for how to make the display scroll, chosen * using the preprocessor directives below */ #if 1 /* This option makes all the lines scroll round at different speeds * which are chosen so that all the scrolls finish at the same time. */ dev->line[y].speed = 256 * dev->line[y].width / widthmax; #elif 1 /* This option pads the shorter lines with spaces so that they all * scroll together. */ dev->line[y].width = widthmax / 2; dev->line[y].speed = 256/2; #else /* This option makes the shorter lines stop after they have rotated * and waits for the longer lines to catch up */ dev->line[y].speed = 256/2; #endif } } /* Repaint once, then check whether there has been a missed repaint * (because active was set when the timer interrupt occurred). If there * has been a missed repaint then paint again. And again. etc. */ for ( ; ; ) { int old_scrollpos = dev->scrollpos; lcd_repaint_screen(dev); /* Let the timer routines repaint the display again */ dev->active = 0; /* Have the timer routines tried to scroll while we were painting? * If not then we can exit */ if (dev->scrollpos == old_scrollpos) break; /* We need to repaint again since the display scrolled while we were * painting last time */ dev->active = 1; } /* Now that access to the display is complete, release the write * semaphore so that other threads can access the buffer. */ ALT_SEM_POST (dev->write_lock); return len; }
int fifoed_avalon_uart_write (fifoed_avalon_uart_state* sp, const char* ptr, int len, int flags) { alt_irq_context context; int no_block; alt_u32 next; int count = len; /* * Construct a flag to indicate whether the device is being accessed in * blocking or non-blocking mode. */ no_block = (flags & O_NONBLOCK); /* * When running in a multi threaded environment, obtain the "write_lock" * semaphore. This ensures that writing to the device is thread-safe. */ ALT_SEM_PEND (sp->write_lock, 0); /* * Loop transferring data from the input buffer to the transmit circular * buffer. The loop is terminated once all the data has been transferred, * or, (if in non-blocking mode) the buffer becomes full. */ while (count) { /* Determine the next slot in the buffer to access */ next = (sp->tx_end + 1) & FIFOED_AVALON_UART_BUF_MSK; /* block waiting for space if necessary */ if (next == sp->tx_start) { if (no_block) { /* Set errno to indicate why this function returned early */ ALT_ERRNO = EWOULDBLOCK; break; } else { /* Block waiting for space in the circular buffer */ /* First, ensure transmit interrupts are enabled to avoid deadlock */ context = alt_irq_disable_all (); sp->ctrl |= (FIFOED_AVALON_UART_CONTROL_TRDY_MSK | FIFOED_AVALON_UART_CONTROL_DCTS_MSK); IOWR_FIFOED_AVALON_UART_CONTROL(sp->base, sp->ctrl); alt_irq_enable_all (context); /* wait for space to come free */ do { /* * When running in a multi-threaded mode, we pend on the write event * flag set in the interrupt service routine. This avoids wasting CPU * cycles waiting in this thread, when we could be doing something * more profitable elsewhere. */ ALT_FLAG_PEND (sp->events, ALT_UART_WRITE_RDY, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); } while ((next == sp->tx_start)); } } count--; /* Add the next character to the transmit buffer */ sp->tx_buf[sp->tx_end] = *ptr++; sp->tx_end = next; } /* * Now that access to the circular buffer is complete, release the write * semaphore so that other threads can access the buffer. */ ALT_SEM_POST (sp->write_lock); /* * Ensure that interrupts are enabled, so that the circular buffer can * drain. */ context = alt_irq_disable_all (); sp->ctrl |= FIFOED_AVALON_UART_CONTROL_TRDY_MSK | FIFOED_AVALON_UART_CONTROL_DCTS_MSK; IOWR_FIFOED_AVALON_UART_CONTROL(sp->base, sp->ctrl); alt_irq_enable_all (context); /* return the number of bytes written */ return (len - count); }
int fifoed_avalon_uart_read (fifoed_avalon_uart_state* sp, char* ptr, int len, int flags) { alt_irq_context context; int block; alt_u32 next; int count = 0; /* * Construct a flag to indicate whether the device is being accessed in * blocking or non-blocking mode. */ block = !(flags & O_NONBLOCK); /* * When running in a multi threaded environment, obtain the "read_lock" * semaphore. This ensures that reading from the device is thread-safe. */ ALT_SEM_PEND (sp->read_lock, 0); /* * Calculate which slot in the circular buffer is the next one to read * data from. */ next = (sp->rx_start + 1) & FIFOED_AVALON_UART_BUF_MSK; /* * Loop, copying data from the circular buffer to the destination address * supplied in "ptr". This loop is terminated when the required number of * bytes have been read. If the circular buffer is empty, and no data has * been read, then the loop will block (when in blocking mode). * * If the circular buffer is empty, and some data has already been * transferred, or the device is being accessed in non-blocking mode, then * the loop terminates without necessarily reading all the requested data. */ do { /* * Read the required amount of data, until the circular buffer runs * empty */ while ((count < len) && (sp->rx_start != sp->rx_end)) { count++; *ptr++ = sp->rx_buf[sp->rx_start]; sp->rx_start = (++sp->rx_start) & FIFOED_AVALON_UART_BUF_MSK; } /* * If no data has been transferred, the circular buffer is empty, and * this is not a non-blocking access, block waiting for data to arrive. */ if (!count && (sp->rx_start == sp->rx_end)) { if (!block) { /* Set errno to indicate the reason we're not returning any data */ ALT_ERRNO = EWOULDBLOCK; break; } else { /* Block waiting for some data to arrive */ /* First, ensure read interrupts are enabled to avoid deadlock */ context = alt_irq_disable_all (); sp->ctrl |= FIFOED_AVALON_UART_CONTROL_RRDY_MSK; IOWR_FIFOED_AVALON_UART_CONTROL(sp->base, sp->ctrl); alt_irq_enable_all (context); /* * When running in a multi-threaded mode, we pend on the read event * flag set in the interrupt service routine. This avoids wasting CPU * cycles waiting in this thread, when we could be doing something more * profitable elsewhere. */ ALT_FLAG_PEND (sp->events, ALT_UART_READ_RDY, OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME, 0); } } } while (!count && len); /* * Now that access to the circular buffer is complete, release the read * semaphore so that other threads can access the buffer. */ ALT_SEM_POST (sp->read_lock); /* * Ensure that interrupts are enabled, so that the circular buffer can * re-fill. */ context = alt_irq_disable_all (); sp->ctrl |= FIFOED_AVALON_UART_CONTROL_RRDY_MSK; IOWR_FIFOED_AVALON_UART_CONTROL(sp->base, sp->ctrl); alt_irq_enable_all (context); /* Return the number of bytes read */ return count; }
void getcontrols(void *pdata) { int data, i; char cmd[3]; for (i = 0; i < sizeof(cmd)/sizeof(cmd[0]); i++) { cmd[i] = 0; } i = 0; /* read and echo characters */ while(1) { data = *(JTAG_UART_ptr); // read the JTAG_UART data register if (data & 0x00008000) // check RVALID to see if there is new data { data = data & 0x000000FF; // the data is in the least significant byte /* echo the character */ while ((char) data == '1' || (char) data == '2') { OSTimeDly(1); cmd[0] = data; data = *(JTAG_UART_ptr); // read the JTAG_UART data register if (data & 0x00008000) // check RVALID to see if there is new data { data = data & 0x000000FF; // the data is in the least significant byte while (1) { OSTimeDly(1); cmd[1] = data; data = *(JTAG_UART_ptr); // read the JTAG_UART data register if (data & 0x00008000) // check RVALID to see if there is new data { data = data & 0x000000FF; // the data is in the least significant byte while ((char) data == 'r' || (char) data == 'p') { OSTimeDly(1); cmd[2] = data; break; } } break; } } break; } if (cmd[0] != 0 && cmd[1] != 0 && cmd[2] != 0) { ALT_SEM_PEND(display,0); // printf("\n"); // for (i = 0; i < sizeof(cmd)/sizeof(cmd[0]); i++) // { // printf("%c", cmd[i]); // } // printf("\n"); alt_u16 x; alt_u8 y; switch(cmd[1]) { case 'd': x = 81; y= 66; break; case 'c': x = 81; y = 81; break; case 'e': x = 216; y = 66; break; case 'z': x = 216; y = 81; break; case 'h': x = 81; y = 104; break; case 'g': x = 81; y = 134; break; case 'l': x = 65; y = 118; break; case 'r': x = 96; y= 118; break; case 'f': x = 133; y= 118; break; case 's': x = 163; y = 118; break; case 'y': x = 216; y = 102; break; case 'x': x = 201; y = 117; break; case 'b': x = 231; y = 117; break; case 'a': x = 216; y = 132; break; default: x = 0; y = 0; break; } switch(cmd[2]) { case 'p': drawrectangle(pixel_buffer_start,x,y,8,8,0xFFFF); int i; int err; playtone(5000,10); playtone(8000,10); playtone(5000,10); *(RED_LED_ptr) = (1<<3); break; case 'r': drawrectangle(pixel_buffer_start,x,y,8,8,0x0000); *(RED_LED_ptr) = (0<<3); break; } for (i = 0; i < sizeof(cmd)/sizeof(cmd[0]); i++) { cmd[i] = 0; } i = 0; } OSTimeDly(1); ALT_SEM_POST(display); } } }