|  |  |  | @ -42,10 +42,10 @@ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     #define N_USER_CHARS    8 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     #define TOP_LEFT      0x01 | 
			
		
	
		
			
				
					|  |  |  |  |     #define TOP_RIGHT     0x02 | 
			
		
	
		
			
				
					|  |  |  |  |     #define LOWER_LEFT    0x04 | 
			
		
	
		
			
				
					|  |  |  |  |     #define LOWER_RIGHT   0x08 | 
			
		
	
		
			
				
					|  |  |  |  |     #define TOP_LEFT      _BV(0) | 
			
		
	
		
			
				
					|  |  |  |  |     #define TOP_RIGHT     _BV(1) | 
			
		
	
		
			
				
					|  |  |  |  |     #define LOWER_LEFT    _BV(2) | 
			
		
	
		
			
				
					|  |  |  |  |     #define LOWER_RIGHT   _BV(3) | 
			
		
	
		
			
				
					|  |  |  |  |   #endif | 
			
		
	
		
			
				
					|  |  |  |  | #endif | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -1057,9 +1057,7 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   #endif // LCD_HAS_SLOW_BUTTONS
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // ULTIPANEL
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(LCD_HAS_STATUS_INDICATORS) | 
			
		
	
		
			
				
					|  |  |  |  |   #if ENABLED(LCD_HAS_STATUS_INDICATORS) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     static void lcd_implementation_update_indicators() { | 
			
		
	
		
			
				
					|  |  |  |  |       // Set the LEDS - referred to as backlights by the LiquidTWI2 library
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -1094,9 +1092,9 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // LCD_HAS_STATUS_INDICATORS
 | 
			
		
	
		
			
				
					|  |  |  |  |   #endif // LCD_HAS_STATUS_INDICATORS
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #if ENABLED(AUTO_BED_LEVELING_UBL) | 
			
		
	
		
			
				
					|  |  |  |  |   #if ENABLED(AUTO_BED_LEVELING_UBL) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /**
 | 
			
		
	
		
			
				
					|  |  |  |  |       Possible map screens: | 
			
		
	
	
		
			
				
					|  |  |  | @ -1118,40 +1116,57 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  |              | +-------+  Z:00.000| | 
			
		
	
		
			
				
					|  |  |  |  |     */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   struct custom_char { | 
			
		
	
		
			
				
					|  |  |  |  |     typedef struct { | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t custom_char_bits[ULTRA_Y_PIXELS_PER_CHAR]; | 
			
		
	
		
			
				
					|  |  |  |  |   }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   struct coordinate pixel_location(uint8_t x, uint8_t y); | 
			
		
	
		
			
				
					|  |  |  |  |     } custom_char; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   struct coordinate { | 
			
		
	
		
			
				
					|  |  |  |  |           uint8_t column; | 
			
		
	
		
			
				
					|  |  |  |  |           uint8_t row; | 
			
		
	
		
			
				
					|  |  |  |  |           uint8_t y_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  |           uint8_t x_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  |     typedef struct { | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t column, row; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t y_pixel_offset, x_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |   }; | 
			
		
	
		
			
				
					|  |  |  |  |     } coordinate; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   void add_edges_to_custom_char(struct custom_char *custom, struct coordinate *ul, struct coordinate *lr, struct coordinate *brc, uint8_t cell_location); | 
			
		
	
		
			
				
					|  |  |  |  |   extern custom_char user_defined_chars[N_USER_CHARS]; | 
			
		
	
		
			
				
					|  |  |  |  |   inline static void CLEAR_CUSTOM_CHAR(struct custom_char *cc) { uint8_t j; for (j = 0; j < ULTRA_Y_PIXELS_PER_CHAR; j++) cc->custom_char_bits[j] = 0; } | 
			
		
	
		
			
				
					|  |  |  |  |     void add_edges_to_custom_char(custom_char * const custom, coordinate * const ul, coordinate * const lr, coordinate * const brc, const uint8_t cell_location); | 
			
		
	
		
			
				
					|  |  |  |  |     FORCE_INLINE static void clear_custom_char(custom_char * const cc) { ZERO(cc->custom_char_bits); } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /*
 | 
			
		
	
		
			
				
					|  |  |  |  |   void dump_custom_char(char *title, struct custom_char *c) {   // This debug routine should be deleted by anybody that sees it.  It doesn't belong here
 | 
			
		
	
		
			
				
					|  |  |  |  |     int i, j;                                                     // But I'm leaving it for now until we know the 20x4 Radar Map is working right.
 | 
			
		
	
		
			
				
					|  |  |  |  |     SERIAL_PROTOCOLLN(title);                                   // We will need it again if any funny lines show up on the mesh points.
 | 
			
		
	
		
			
				
					|  |  |  |  |     for(j=0; j<8; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |       for(i=7; i>=0; i--) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (c->custom_char_bits[j] & (0x01 << i)) | 
			
		
	
		
			
				
					|  |  |  |  |           SERIAL_PROTOCOL("1"); | 
			
		
	
		
			
				
					|  |  |  |  |         else | 
			
		
	
		
			
				
					|  |  |  |  |           SERIAL_PROTOCOL("0"); | 
			
		
	
		
			
				
					|  |  |  |  |     // This debug routine should be deleted by anybody that sees it.  It doesn't belong here
 | 
			
		
	
		
			
				
					|  |  |  |  |     // But I'm leaving it for now until we know the 20x4 Radar Map is working right.
 | 
			
		
	
		
			
				
					|  |  |  |  |     // We may need it again if any funny lines show up on the mesh points.
 | 
			
		
	
		
			
				
					|  |  |  |  |     void dump_custom_char(char *title, custom_char *c) { | 
			
		
	
		
			
				
					|  |  |  |  |       SERIAL_PROTOCOLLN(title); | 
			
		
	
		
			
				
					|  |  |  |  |       for (uint8_t j = 0; j < 8; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |         for (uint8_t i = 7; i >= 0; i--) | 
			
		
	
		
			
				
					|  |  |  |  |           SERIAL_PROTOCOLCHAR(TEST(c->custom_char_bits[j], i) ? '1' : '0'); | 
			
		
	
		
			
				
					|  |  |  |  |         SERIAL_EOL(); | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |       SERIAL_PROTOCOL("\n"); | 
			
		
	
		
			
				
					|  |  |  |  |       SERIAL_EOL(); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     SERIAL_PROTOCOL("\n"); | 
			
		
	
		
			
				
					|  |  |  |  |     //*/
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     coordinate pixel_location(int16_t x, int16_t y) { | 
			
		
	
		
			
				
					|  |  |  |  |       coordinate ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |       int16_t xp, yp, r, c; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       x++; y++; // +1 because lines on the left and top
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       c = x / (ULTRA_X_PIXELS_PER_CHAR); | 
			
		
	
		
			
				
					|  |  |  |  |       r = y / (ULTRA_Y_PIXELS_PER_CHAR); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       ret_val.column = c; | 
			
		
	
		
			
				
					|  |  |  |  |       ret_val.row    = r; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       xp = x - c * (ULTRA_X_PIXELS_PER_CHAR);   // get the pixel offsets into the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |       xp = ULTRA_X_PIXELS_PER_CHAR - 1 - xp;    // column within relevant character cell (0 on the right)
 | 
			
		
	
		
			
				
					|  |  |  |  |       yp = y - r * (ULTRA_Y_PIXELS_PER_CHAR); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       ret_val.x_pixel_mask   = _BV(xp); | 
			
		
	
		
			
				
					|  |  |  |  |       ret_val.x_pixel_offset = xp; | 
			
		
	
		
			
				
					|  |  |  |  |       ret_val.y_pixel_offset = yp; | 
			
		
	
		
			
				
					|  |  |  |  |       return ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |   */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     coordinate pixel_location(uint8_t x, uint8_t y) { return pixel_location((int16_t)x, (int16_t)y); } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     void lcd_implementation_ubl_plot(uint8_t x, uint8_t inverted_y) { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -1188,17 +1203,13 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       #else // 16x4 or 20x4 display
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       struct coordinate upper_left, lower_right, bottom_right_corner; | 
			
		
	
		
			
				
					|  |  |  |  |       struct custom_char new_char; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t i, j, k, l, m, n, n_rows, n_cols, y; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t bottom_line, right_edge; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t x_map_pixels, y_map_pixels; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt; | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t suppress_x_offset=0, suppress_y_offset=0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       //  ********************************************************
 | 
			
		
	
		
			
				
					|  |  |  |  |       //  ************ Clear and setup everything        *********
 | 
			
		
	
		
			
				
					|  |  |  |  |       //  ********************************************************
 | 
			
		
	
		
			
				
					|  |  |  |  |         coordinate upper_left, lower_right, bottom_right_corner; | 
			
		
	
		
			
				
					|  |  |  |  |         custom_char new_char; | 
			
		
	
		
			
				
					|  |  |  |  |         uint8_t i, j, k, l, m, n, n_rows, n_cols, y, | 
			
		
	
		
			
				
					|  |  |  |  |                 bottom_line, right_edge, | 
			
		
	
		
			
				
					|  |  |  |  |                 x_map_pixels, y_map_pixels, | 
			
		
	
		
			
				
					|  |  |  |  |                 pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt, | 
			
		
	
		
			
				
					|  |  |  |  |                 suppress_x_offset = 0, suppress_y_offset = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         y = GRID_MAX_POINTS_Y - inverted_y - 1; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -1209,93 +1220,93 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd_implementation_clear(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       x_map_pixels = ULTRA_X_PIXELS_PER_CHAR * ULTRA_COLUMNS_FOR_MESH_MAP - 2;  // minus 2 because we are drawing a box around the map
 | 
			
		
	
		
			
				
					|  |  |  |  |       y_map_pixels = ULTRA_Y_PIXELS_PER_CHAR * ULTRA_ROWS_FOR_MESH_MAP - 2; | 
			
		
	
		
			
				
					|  |  |  |  |         x_map_pixels = (ULTRA_X_PIXELS_PER_CHAR) * (ULTRA_COLUMNS_FOR_MESH_MAP) - 2;  // minus 2 because we are drawing a box around the map
 | 
			
		
	
		
			
				
					|  |  |  |  |         y_map_pixels = (ULTRA_Y_PIXELS_PER_CHAR) * (ULTRA_ROWS_FOR_MESH_MAP) - 2; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       pixels_per_X_mesh_pnt = x_map_pixels / GRID_MAX_POINTS_X; | 
			
		
	
		
			
				
					|  |  |  |  |       pixels_per_Y_mesh_pnt = y_map_pixels / GRID_MAX_POINTS_Y; | 
			
		
	
		
			
				
					|  |  |  |  |         pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X); | 
			
		
	
		
			
				
					|  |  |  |  |         pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (pixels_per_X_mesh_pnt >= ULTRA_X_PIXELS_PER_CHAR)  {                  // There are only 2 custom characters available, so the X
 | 
			
		
	
		
			
				
					|  |  |  |  |         pixels_per_X_mesh_pnt = ULTRA_X_PIXELS_PER_CHAR;                        // size of the mesh point needs to fit within them independent
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (pixels_per_x_mesh_pnt >= ULTRA_X_PIXELS_PER_CHAR) {         // There are only 2 custom characters available, so the X
 | 
			
		
	
		
			
				
					|  |  |  |  |           pixels_per_x_mesh_pnt = ULTRA_X_PIXELS_PER_CHAR;              // size of the mesh point needs to fit within them independent
 | 
			
		
	
		
			
				
					|  |  |  |  |           suppress_x_offset = 1;                                        // of where the starting pixel is located.
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (pixels_per_Y_mesh_pnt >= ULTRA_Y_PIXELS_PER_CHAR) {                   // There are only 2 custom characters available, so the Y
 | 
			
		
	
		
			
				
					|  |  |  |  |         pixels_per_Y_mesh_pnt = ULTRA_Y_PIXELS_PER_CHAR;                        // size of the mesh point needs to fit within them independent
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (pixels_per_y_mesh_pnt >= ULTRA_Y_PIXELS_PER_CHAR) {         // There are only 2 custom characters available, so the Y
 | 
			
		
	
		
			
				
					|  |  |  |  |           pixels_per_y_mesh_pnt = ULTRA_Y_PIXELS_PER_CHAR;              // size of the mesh point needs to fit within them independent
 | 
			
		
	
		
			
				
					|  |  |  |  |           suppress_y_offset = 1;                                        // of where the starting pixel is located.
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       x_map_pixels = pixels_per_X_mesh_pnt * GRID_MAX_POINTS_X;                 // now we have the right number of pixels to make both
 | 
			
		
	
		
			
				
					|  |  |  |  |       y_map_pixels = pixels_per_Y_mesh_pnt * GRID_MAX_POINTS_Y;                 // directions fit nicely
 | 
			
		
	
		
			
				
					|  |  |  |  |         x_map_pixels = pixels_per_x_mesh_pnt * (GRID_MAX_POINTS_X);     // now we have the right number of pixels to make both
 | 
			
		
	
		
			
				
					|  |  |  |  |         y_map_pixels = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y);     // directions fit nicely
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       right_edge = pixels_per_X_mesh_pnt * GRID_MAX_POINTS_X + 1;               // find location of right edge within the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |       bottom_line= pixels_per_Y_mesh_pnt * GRID_MAX_POINTS_Y + 1;               // find location of bottome line within the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         right_edge = pixels_per_x_mesh_pnt * (GRID_MAX_POINTS_X) + 1;   // find location of right edge within the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         bottom_line= pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y) + 1;   // find location of bottome line within the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       n_rows = (bottom_line / ULTRA_Y_PIXELS_PER_CHAR) + 1; | 
			
		
	
		
			
				
					|  |  |  |  |       n_cols = (right_edge / ULTRA_X_PIXELS_PER_CHAR) + 1; | 
			
		
	
		
			
				
					|  |  |  |  |         n_rows = bottom_line / (ULTRA_Y_PIXELS_PER_CHAR) + 1; | 
			
		
	
		
			
				
					|  |  |  |  |         n_cols = right_edge / (ULTRA_X_PIXELS_PER_CHAR) + 1; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for (i = 0; i < n_cols; i++) { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(i, 0); | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.print((char) 0x00);                    // top line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.print((char)0x00);                     // top line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.setCursor(i, n_rows-1); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(i, n_rows - 1); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x01);                           // bottom line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = 0; j < n_rows; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(0, j); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x02);                           // Left edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.setCursor(n_cols-1, j); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(n_cols - 1, j); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x03);                           // right edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       //
 | 
			
		
	
		
			
				
					|  |  |  |  |       /* if the entire 4th row is not in use, do not put vertical bars all the way down to the bottom of the display */ | 
			
		
	
		
			
				
					|  |  |  |  |       //
 | 
			
		
	
		
			
				
					|  |  |  |  |         /**
 | 
			
		
	
		
			
				
					|  |  |  |  |          * If the entire 4th row is not in use, do not put vertical bars all the way down to the bottom of the display | 
			
		
	
		
			
				
					|  |  |  |  |          */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       k = pixels_per_Y_mesh_pnt * GRID_MAX_POINTS_Y + 2; | 
			
		
	
		
			
				
					|  |  |  |  |       l = ULTRA_Y_PIXELS_PER_CHAR * n_rows; | 
			
		
	
		
			
				
					|  |  |  |  |       if ((k != l) && ((l-k)>=ULTRA_Y_PIXELS_PER_CHAR/2)) { | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.setCursor(0, n_rows-1);            // left edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         k = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y) + 2; | 
			
		
	
		
			
				
					|  |  |  |  |         l = (ULTRA_Y_PIXELS_PER_CHAR) * n_rows; | 
			
		
	
		
			
				
					|  |  |  |  |         if (l > k && l - k >= (ULTRA_Y_PIXELS_PER_CHAR) / 2) { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(0, n_rows - 1);            // left edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(' '); | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.setCursor(n_cols-1, n_rows-1);     // right edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(n_cols - 1, n_rows - 1);   // right edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(' '); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |       new_char.custom_char_bits[0] = (unsigned char) 0B11111;                // char #0 is used for the top line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |       lcd.createChar(0, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         new_char.custom_char_bits[0] = 0B11111U;              // char #0 is used for the top line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(0, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |       k = GRID_MAX_POINTS_Y * pixels_per_Y_mesh_pnt + 1;                     // row of pixels for the bottom box line
 | 
			
		
	
		
			
				
					|  |  |  |  |       l = k % ULTRA_Y_PIXELS_PER_CHAR;                                       // row within relivant character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |       new_char.custom_char_bits[l] = (unsigned char) 0B11111;                // char #1 is used for the bottom line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |       lcd.createChar(1, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         k = (GRID_MAX_POINTS_Y) * pixels_per_y_mesh_pnt + 1;  // row of pixels for the bottom box line
 | 
			
		
	
		
			
				
					|  |  |  |  |         l = k % (ULTRA_Y_PIXELS_PER_CHAR);                    // row within relevant character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         new_char.custom_char_bits[l] = 0B11111U;              // char #1 is used for the bottom line of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(1, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = 0; j < ULTRA_Y_PIXELS_PER_CHAR; j++) | 
			
		
	
		
			
				
					|  |  |  |  |         new_char.custom_char_bits[j] = (unsigned char) 0B10000;              // char #2 is used for the left edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |       lcd.createChar(2, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           new_char.custom_char_bits[j] = 0B10000U;            // char #2 is used for the left edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(2, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |       m = GRID_MAX_POINTS_X * pixels_per_X_mesh_pnt + 1;                     // column of pixels for the right box line
 | 
			
		
	
		
			
				
					|  |  |  |  |       n = m % ULTRA_X_PIXELS_PER_CHAR;                                       // column within relivant character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |       i = ULTRA_X_PIXELS_PER_CHAR - 1 - n;                                   // column within relivant character cell (0 on the right)
 | 
			
		
	
		
			
				
					|  |  |  |  |         clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         m = (GRID_MAX_POINTS_X) * pixels_per_x_mesh_pnt + 1;  // Column of pixels for the right box line
 | 
			
		
	
		
			
				
					|  |  |  |  |         n = m % (ULTRA_X_PIXELS_PER_CHAR);                    // Column within relevant character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         i = ULTRA_X_PIXELS_PER_CHAR - 1 - n;                  // Column within relevant character cell (0 on the right)
 | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = 0; j < ULTRA_Y_PIXELS_PER_CHAR; j++) | 
			
		
	
		
			
				
					|  |  |  |  |         new_char.custom_char_bits[j] = (unsigned char) 0B00001 << i;         // char #3 is used for the right edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |       lcd.createChar(3, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           new_char.custom_char_bits[j] = (uint8_t)_BV(i);     // Char #3 is used for the right edge of the box
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(3, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       i = x*pixels_per_X_mesh_pnt - suppress_x_offset; | 
			
		
	
		
			
				
					|  |  |  |  |       j = y*pixels_per_Y_mesh_pnt - suppress_y_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         i = x * pixels_per_x_mesh_pnt - suppress_x_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         j = y * pixels_per_y_mesh_pnt - suppress_y_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         upper_left = pixel_location(i, j); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       k = (x+1)*pixels_per_X_mesh_pnt-1-suppress_x_offset; | 
			
		
	
		
			
				
					|  |  |  |  |       l = (y+1)*pixels_per_Y_mesh_pnt-1-suppress_y_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         k = (x + 1) * pixels_per_x_mesh_pnt - 1 - suppress_x_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         l = (y + 1) * pixels_per_y_mesh_pnt - 1 - suppress_y_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         lower_right = pixel_location(k, l); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         bottom_right_corner = pixel_location(x_map_pixels, y_map_pixels); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       /*
 | 
			
		
	
		
			
				
					|  |  |  |  |         /**
 | 
			
		
	
		
			
				
					|  |  |  |  |          * First, handle the simple case where everything is within a single character cell. | 
			
		
	
		
			
				
					|  |  |  |  |          * If part of the Mesh Plot is outside of this character cell, we will follow up | 
			
		
	
		
			
				
					|  |  |  |  |          * and deal with that next. | 
			
		
	
	
		
			
				
					|  |  |  | @ -1303,40 +1314,37 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         //dump_custom_char("at entry:", &new_char);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |       for(j=upper_left.y_pixel_offset; j<upper_left.y_pixel_offset+pixels_per_Y_mesh_pnt; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (j >= ULTRA_Y_PIXELS_PER_CHAR) | 
			
		
	
		
			
				
					|  |  |  |  |           break; | 
			
		
	
		
			
				
					|  |  |  |  |         i=upper_left.x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |         for(k=0; k<pixels_per_X_mesh_pnt; k++)  { | 
			
		
	
		
			
				
					|  |  |  |  |         clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         const uint8_t ypix = min(upper_left.y_pixel_offset + pixels_per_y_mesh_pnt, ULTRA_Y_PIXELS_PER_CHAR); | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = upper_left.y_pixel_offset; j < ypix; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |           i = upper_left.x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |           for (k = 0; k < pixels_per_x_mesh_pnt; k++) { | 
			
		
	
		
			
				
					|  |  |  |  |             new_char.custom_char_bits[j] |= i; | 
			
		
	
		
			
				
					|  |  |  |  |           i = i >> 1; | 
			
		
	
		
			
				
					|  |  |  |  |             i >>= 1; | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         //dump_custom_char("after loops:", &new_char);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, TOP_LEFT); | 
			
		
	
		
			
				
					|  |  |  |  |         //dump_custom_char("after add edges", &new_char);
 | 
			
		
	
		
			
				
					|  |  |  |  |       lcd.createChar(4, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(4, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.setCursor(upper_left.column, upper_left.row); | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.write(0x04); | 
			
		
	
		
			
				
					|  |  |  |  |         //dump_custom_char("after lcd update:", &new_char);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       /*
 | 
			
		
	
		
			
				
					|  |  |  |  |         /**
 | 
			
		
	
		
			
				
					|  |  |  |  |          * Next, check for two side by side character cells being used to display the Mesh Point | 
			
		
	
		
			
				
					|  |  |  |  |          * If found...  do the right hand character cell next. | 
			
		
	
		
			
				
					|  |  |  |  |          */ | 
			
		
	
		
			
				
					|  |  |  |  |       if (upper_left.column+1 == lower_right.column) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (upper_left.column == lower_right.column - 1) { | 
			
		
	
		
			
				
					|  |  |  |  |           l = upper_left.x_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  |         CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = upper_left.y_pixel_offset; j < upper_left.y_pixel_offset + pixels_per_Y_mesh_pnt; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |           if (j >= ULTRA_Y_PIXELS_PER_CHAR) | 
			
		
	
		
			
				
					|  |  |  |  |             break; | 
			
		
	
		
			
				
					|  |  |  |  |           i=0x01 << (ULTRA_X_PIXELS_PER_CHAR-1);                  // fill in the left side of the right character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           for(k=0; k<pixels_per_X_mesh_pnt-1-l; k++)  { | 
			
		
	
		
			
				
					|  |  |  |  |           clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           for (j = upper_left.y_pixel_offset; j < ypix; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |             i = _BV(ULTRA_X_PIXELS_PER_CHAR - 1);                  // Fill in the left side of the right character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |             for (k = 0; k < pixels_per_x_mesh_pnt - 1 - l; k++) { | 
			
		
	
		
			
				
					|  |  |  |  |               new_char.custom_char_bits[j] |= i; | 
			
		
	
		
			
				
					|  |  |  |  |             i = i >> 1; | 
			
		
	
		
			
				
					|  |  |  |  |               i >>= 1; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |           add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, TOP_RIGHT); | 
			
		
	
	
		
			
				
					|  |  |  | @ -1347,20 +1355,18 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x05); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       /*
 | 
			
		
	
		
			
				
					|  |  |  |  |         /**
 | 
			
		
	
		
			
				
					|  |  |  |  |          * Next, check for two character cells stacked on top of each other being used to display the Mesh Point | 
			
		
	
		
			
				
					|  |  |  |  |          */ | 
			
		
	
		
			
				
					|  |  |  |  |       if (upper_left.row+1 == lower_right.row) { | 
			
		
	
		
			
				
					|  |  |  |  |         l = ULTRA_Y_PIXELS_PER_CHAR - upper_left.y_pixel_offset;        // number of pixel rows in top character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         k = pixels_per_Y_mesh_pnt - l;                                  // number of pixel rows in bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         for(j=0; j<k; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |           i=upper_left.x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |           for(m=0; m<pixels_per_X_mesh_pnt; m++)  {                     // fill in the top side of the bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (upper_left.row == lower_right.row - 1) { | 
			
		
	
		
			
				
					|  |  |  |  |           l = ULTRA_Y_PIXELS_PER_CHAR - upper_left.y_pixel_offset;  // Number of pixel rows in top character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = pixels_per_y_mesh_pnt - l;                            // Number of pixel rows in bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           for (j = 0; j < k; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |             i = upper_left.x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |             for (m = 0; m < pixels_per_x_mesh_pnt; m++) {           // Fill in the top side of the bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |               new_char.custom_char_bits[j] |= i; | 
			
		
	
		
			
				
					|  |  |  |  |             i = i >> 1; | 
			
		
	
		
			
				
					|  |  |  |  |             if (!i) | 
			
		
	
		
			
				
					|  |  |  |  |               break; | 
			
		
	
		
			
				
					|  |  |  |  |               if (!(i >>= 1)) break; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |           add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, LOWER_LEFT); | 
			
		
	
	
		
			
				
					|  |  |  | @ -1370,26 +1376,26 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x06); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       /*
 | 
			
		
	
		
			
				
					|  |  |  |  |         /**
 | 
			
		
	
		
			
				
					|  |  |  |  |          * Next, check for four character cells being used to display the Mesh Point.  If that is | 
			
		
	
		
			
				
					|  |  |  |  |          * what is here, we work to fill in the character cell that is down one and to the right one | 
			
		
	
		
			
				
					|  |  |  |  |          * from the upper_left character cell. | 
			
		
	
		
			
				
					|  |  |  |  |          */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (upper_left.column+1 == lower_right.column && upper_left.row+1 == lower_right.row) { | 
			
		
	
		
			
				
					|  |  |  |  |         l = ULTRA_Y_PIXELS_PER_CHAR - upper_left.y_pixel_offset;        // number of pixel rows in top character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         k = pixels_per_Y_mesh_pnt - l;                                  // number of pixel rows in bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |         CLEAR_CUSTOM_CHAR(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |         for (j = 0; j<k; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (upper_left.column == lower_right.column - 1 && upper_left.row == lower_right.row - 1) { | 
			
		
	
		
			
				
					|  |  |  |  |           l = ULTRA_Y_PIXELS_PER_CHAR - upper_left.y_pixel_offset;   // Number of pixel rows in top character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = pixels_per_y_mesh_pnt - l;                             // Number of pixel rows in bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           clear_custom_char(&new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           for (j = 0; j < k; j++) { | 
			
		
	
		
			
				
					|  |  |  |  |             l = upper_left.x_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  |           i = 0x01 << (ULTRA_X_PIXELS_PER_CHAR - 1);                    // fill in the left side of the right character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           for (m = 0; m<pixels_per_X_mesh_pnt - 1 - l; m++) {           // fill in the top side of the bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |             i = _BV(ULTRA_X_PIXELS_PER_CHAR - 1);                    // Fill in the left side of the right character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |             for (m = 0; m < pixels_per_x_mesh_pnt - 1 - l; m++) {    // Fill in the top side of the bottom character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |               new_char.custom_char_bits[j] |= i; | 
			
		
	
		
			
				
					|  |  |  |  |             i = i >> 1; | 
			
		
	
		
			
				
					|  |  |  |  |               i >>= 1; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |           } | 
			
		
	
		
			
				
					|  |  |  |  |           add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, LOWER_RIGHT); | 
			
		
	
		
			
				
					|  |  |  |  |         lcd.createChar(7, (uint8_t *) &new_char); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.createChar(7, (uint8_t*)&new_char); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.setCursor(lower_right.column, lower_right.row); | 
			
		
	
		
			
				
					|  |  |  |  |           lcd.write(0x07); | 
			
		
	
	
		
			
				
					|  |  |  | @ -1438,178 +1444,92 @@ static void lcd_implementation_status_screen() { | 
			
		
	
		
			
				
					|  |  |  |  |           lcd_printPGM(PSTR(" -----")); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       #endif // LCD_HEIGHT > 3
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     return; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | void add_edges_to_custom_char(struct custom_char *custom, struct coordinate *ul, struct coordinate *lr, struct coordinate *brc, unsigned char cell_location) { | 
			
		
	
		
			
				
					|  |  |  |  |   unsigned char i, k; | 
			
		
	
		
			
				
					|  |  |  |  |   int n_rows, n_cols; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   n_rows = lr->row    - ul->row    + 1; | 
			
		
	
		
			
				
					|  |  |  |  |     void add_edges_to_custom_char(custom_char * const custom, coordinate * const ul, coordinate * const lr, coordinate * const brc, uint8_t cell_location) { | 
			
		
	
		
			
				
					|  |  |  |  |       uint8_t i, k; | 
			
		
	
		
			
				
					|  |  |  |  |       int16_t n_rows = lr->row    - ul->row    + 1, | 
			
		
	
		
			
				
					|  |  |  |  |               n_cols = lr->column - ul->column + 1; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /*
 | 
			
		
	
		
			
				
					|  |  |  |  |       /**
 | 
			
		
	
		
			
				
					|  |  |  |  |        * Check if Top line of box needs to be filled in | 
			
		
	
		
			
				
					|  |  |  |  |        */ | 
			
		
	
		
			
				
					|  |  |  |  |   if ((ul->row == 0) && ((cell_location&TOP_LEFT) || (cell_location&TOP_RIGHT))) {   // Only fill in the top line for the top character cells
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (ul->row == 0 && ((cell_location & TOP_LEFT) || (cell_location & TOP_RIGHT))) {   // Only fill in the top line for the top character cells
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (n_cols == 1) { | 
			
		
	
		
			
				
					|  |  |  |  |           if (ul->column != brc->column) | 
			
		
	
		
			
				
					|  |  |  |  |         custom->custom_char_bits[0] = 0xff;                              // single column in middle
 | 
			
		
	
		
			
				
					|  |  |  |  |       else { | 
			
		
	
		
			
				
					|  |  |  |  |         for (i = brc->x_pixel_offset; i<ULTRA_X_PIXELS_PER_CHAR; i++)    // single column on right side
 | 
			
		
	
		
			
				
					|  |  |  |  |           custom->custom_char_bits[0] |= 0x01 << i; | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     }  | 
			
		
	
		
			
				
					|  |  |  |  |     else {                                                             | 
			
		
	
		
			
				
					|  |  |  |  |       if (cell_location & TOP_LEFT) | 
			
		
	
		
			
				
					|  |  |  |  |         custom->custom_char_bits[0] = 0xff;                              // multiple column in the middle
 | 
			
		
	
		
			
				
					|  |  |  |  |             custom->custom_char_bits[0] = 0xFF;                             // Single column in middle
 | 
			
		
	
		
			
				
					|  |  |  |  |           else | 
			
		
	
		
			
				
					|  |  |  |  |         if (lr->column != brc->column)                                      | 
			
		
	
		
			
				
					|  |  |  |  |           custom->custom_char_bits[0] = 0xff;                            // multiple column with right cell in middle
 | 
			
		
	
		
			
				
					|  |  |  |  |         else { | 
			
		
	
		
			
				
					|  |  |  |  |           for (i = brc->x_pixel_offset; i<ULTRA_X_PIXELS_PER_CHAR; i++) | 
			
		
	
		
			
				
					|  |  |  |  |             custom->custom_char_bits[0] |= 0x01 << i; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |             for (i = brc->x_pixel_offset; i < ULTRA_X_PIXELS_PER_CHAR; i++) // Single column on right side
 | 
			
		
	
		
			
				
					|  |  |  |  |               SBI(custom->custom_char_bits[0], i); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         else if ((cell_location & TOP_LEFT) || lr->column != brc->column)   // Multiple column in the middle or with right cell in middle
 | 
			
		
	
		
			
				
					|  |  |  |  |           custom->custom_char_bits[0] = 0xFF; | 
			
		
	
		
			
				
					|  |  |  |  |         else | 
			
		
	
		
			
				
					|  |  |  |  |           for (i = brc->x_pixel_offset; i < ULTRA_X_PIXELS_PER_CHAR; i++) | 
			
		
	
		
			
				
					|  |  |  |  |             SBI(custom->custom_char_bits[0], i); | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /*
 | 
			
		
	
		
			
				
					|  |  |  |  |       /**
 | 
			
		
	
		
			
				
					|  |  |  |  |        * Check if left line of box needs to be filled in | 
			
		
	
		
			
				
					|  |  |  |  |        */ | 
			
		
	
		
			
				
					|  |  |  |  |       if ((cell_location & TOP_LEFT) || (cell_location & LOWER_LEFT)) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (ul->column == 0) {                                              // Left column of characters on LCD Display
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (ul->row != brc->row) | 
			
		
	
		
			
				
					|  |  |  |  |         k = ULTRA_Y_PIXELS_PER_CHAR;      // if it isn't the last row... do the full character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |       else | 
			
		
	
		
			
				
					|  |  |  |  |         k = brc->y_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = ul->row == brc->row ? brc->y_pixel_offset : ULTRA_Y_PIXELS_PER_CHAR; // If it isn't the last row... do the full character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           for (i = 0; i < k; i++) | 
			
		
	
		
			
				
					|  |  |  |  |         custom->custom_char_bits[i] |= 0x01 << (ULTRA_X_PIXELS_PER_CHAR - 1); | 
			
		
	
		
			
				
					|  |  |  |  |             SBI(custom->custom_char_bits[i], ULTRA_X_PIXELS_PER_CHAR - 1); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   /*
 | 
			
		
	
		
			
				
					|  |  |  |  |       /**
 | 
			
		
	
		
			
				
					|  |  |  |  |        * Check if bottom line of box needs to be filled in | 
			
		
	
		
			
				
					|  |  |  |  |        */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       // Single row of mesh plot cells
 | 
			
		
	
		
			
				
					|  |  |  |  |    if ((n_rows==1) /* && ((cell_location == TOP_LEFT) || (cell_location==TOP_RIGHT)) */) { | 
			
		
	
		
			
				
					|  |  |  |  |      if (ul->row == brc->row)  { | 
			
		
	
		
			
				
					|  |  |  |  |        if (n_cols == 1) {                 // single row, single column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           if (ul->column != brc->column)  | 
			
		
	
		
			
				
					|  |  |  |  |             k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |           else  | 
			
		
	
		
			
				
					|  |  |  |  |             k = brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |        } else { | 
			
		
	
		
			
				
					|  |  |  |  |           if (cell_location & TOP_RIGHT) {  // single row, multiple column case
 | 
			
		
	
		
			
				
					|  |  |  |  |             if(lr->column != brc->column)    | 
			
		
	
		
			
				
					|  |  |  |  |               k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |             else  | 
			
		
	
		
			
				
					|  |  |  |  |               k = brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |           } else                            // single row, left of multiple columns
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (n_rows == 1 /* && (cell_location == TOP_LEFT || cell_location == TOP_RIGHT) */ && ul->row == brc->row) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (n_cols == 1)                                                    // Single row, single column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = ul->column == brc->column ? brc->x_pixel_mask : 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |         else if (cell_location & TOP_RIGHT)                                 // Single row, multiple column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = lr->column == brc->column ? brc->x_pixel_mask : 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |         else                                                                // Single row, left of multiple columns
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |        } | 
			
		
	
		
			
				
					|  |  |  |  |        while (k < (0x01 << ULTRA_X_PIXELS_PER_CHAR)) { | 
			
		
	
		
			
				
					|  |  |  |  |         while (k < _BV(ULTRA_X_PIXELS_PER_CHAR)) { | 
			
		
	
		
			
				
					|  |  |  |  |           custom->custom_char_bits[brc->y_pixel_offset] |= k; | 
			
		
	
		
			
				
					|  |  |  |  |          k = k << 1; | 
			
		
	
		
			
				
					|  |  |  |  |        } | 
			
		
	
		
			
				
					|  |  |  |  |           k <<= 1; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       // Double row of characters on LCD Display
 | 
			
		
	
		
			
				
					|  |  |  |  |       // And this is a bottom custom character
 | 
			
		
	
		
			
				
					|  |  |  |  |    if ((n_rows==2) && ((cell_location == LOWER_LEFT) || (cell_location==LOWER_RIGHT))) { | 
			
		
	
		
			
				
					|  |  |  |  |      if (lr->row == brc->row)  { | 
			
		
	
		
			
				
					|  |  |  |  |        if (n_cols == 1) {                 // double row, single column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           if (ul->column != brc->column)  | 
			
		
	
		
			
				
					|  |  |  |  |             k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |           else  | 
			
		
	
		
			
				
					|  |  |  |  |             k = brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |        } else { | 
			
		
	
		
			
				
					|  |  |  |  |           if (cell_location & LOWER_RIGHT) {  // double row, multiple column case
 | 
			
		
	
		
			
				
					|  |  |  |  |             if(lr->column != brc->column)    | 
			
		
	
		
			
				
					|  |  |  |  |       if (n_rows == 2 && (cell_location == LOWER_LEFT || cell_location == LOWER_RIGHT) && lr->row == brc->row) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (n_cols == 1)                                                  // Double row, single column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = ul->column == brc->column ? brc->x_pixel_mask : 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |         else if (cell_location & LOWER_RIGHT)                             // Double row, multiple column case
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = lr->column == brc->column ? brc->x_pixel_mask : 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |         else                                                              // Double row, left of multiple columns
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |             else  | 
			
		
	
		
			
				
					|  |  |  |  |               k = brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |           } else                            // double row, left of multiple columns
 | 
			
		
	
		
			
				
					|  |  |  |  |             k = 0x01; | 
			
		
	
		
			
				
					|  |  |  |  |        } | 
			
		
	
		
			
				
					|  |  |  |  |        while (k < (0x01 << ULTRA_X_PIXELS_PER_CHAR)) { | 
			
		
	
		
			
				
					|  |  |  |  |         while (k < _BV(ULTRA_X_PIXELS_PER_CHAR)) { | 
			
		
	
		
			
				
					|  |  |  |  |           custom->custom_char_bits[brc->y_pixel_offset] |= k; | 
			
		
	
		
			
				
					|  |  |  |  |          k = k << 1; | 
			
		
	
		
			
				
					|  |  |  |  |        } | 
			
		
	
		
			
				
					|  |  |  |  |           k <<= 1; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |    /*
 | 
			
		
	
		
			
				
					|  |  |  |  |       /**
 | 
			
		
	
		
			
				
					|  |  |  |  |        * Check if right line of box needs to be filled in | 
			
		
	
		
			
				
					|  |  |  |  |        */ | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |    if (lr->column == brc->column) {     // nothing to do if the lower right part of the mesh pnt isn't in the same column as the box line
 | 
			
		
	
		
			
				
					|  |  |  |  |      if ((ul->column == brc->column) || | 
			
		
	
		
			
				
					|  |  |  |  |         ((lr->column == brc->column) && (cell_location&TOP_RIGHT)) || | 
			
		
	
		
			
				
					|  |  |  |  |         ((lr->column == brc->column) && (cell_location&LOWER_RIGHT))) {   // This mesh point is in the same character cell as the right box line
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |        if (ul->row != brc->row) | 
			
		
	
		
			
				
					|  |  |  |  |          k = ULTRA_Y_PIXELS_PER_CHAR;      // if it isn't the last row... do the full character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |        else | 
			
		
	
		
			
				
					|  |  |  |  |          k = brc->y_pixel_offset; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |        for (i = 0; i < k; i++) | 
			
		
	
		
			
				
					|  |  |  |  |          custom->custom_char_bits[i] |= brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |       // Nothing to do if the lower right part of the mesh pnt isn't in the same column as the box line
 | 
			
		
	
		
			
				
					|  |  |  |  |       if (lr->column == brc->column) { | 
			
		
	
		
			
				
					|  |  |  |  |         // This mesh point is in the same character cell as the right box line
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (ul->column == brc->column || (cell_location & TOP_RIGHT) || (cell_location & LOWER_RIGHT)) { | 
			
		
	
		
			
				
					|  |  |  |  |           // If not the last row... do the full character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |           k = ul->row == brc->row ? brc->y_pixel_offset : ULTRA_Y_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  |           for (i = 0; i < k; i++) custom->custom_char_bits[i] |= brc->x_pixel_mask; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   struct coordinate pixel_location(int x, int y) { | 
			
		
	
		
			
				
					|  |  |  |  |     struct coordinate ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |     int xp, yp, r, c; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     x++;  // +1 because there is a line on the left 
 | 
			
		
	
		
			
				
					|  |  |  |  |     y++;  // and a line at the top to make the box
 | 
			
		
	
		
			
				
					|  |  |  |  |   #endif // AUTO_BED_LEVELING_UBL
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     c = x / ULTRA_X_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  |     r = y / ULTRA_Y_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.column = c; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.row    = r; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     xp = x - c * ULTRA_X_PIXELS_PER_CHAR;   // get the pixel offsets into the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |     xp = ULTRA_X_PIXELS_PER_CHAR - 1 - xp;  // column within relivant character cell (0 on the right)
 | 
			
		
	
		
			
				
					|  |  |  |  |     yp = y - r * ULTRA_Y_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.x_pixel_mask   = 0x01 << xp; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.x_pixel_offset = xp; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.y_pixel_offset = yp; | 
			
		
	
		
			
				
					|  |  |  |  |     return ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   struct coordinate pixel_location(uint8_t x, uint8_t y) { | 
			
		
	
		
			
				
					|  |  |  |  |     struct coordinate ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |     uint8_t xp, yp, r, c; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     x++;  // +1 because there is a line on the left
 | 
			
		
	
		
			
				
					|  |  |  |  |     y++;  // and a line at the top to make the box
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     c = x / ULTRA_X_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  |     r = y / ULTRA_Y_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.column = c; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.row    = r; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     xp = x - c * ULTRA_X_PIXELS_PER_CHAR;   // get the pixel offsets into the character cell
 | 
			
		
	
		
			
				
					|  |  |  |  |     xp = ULTRA_X_PIXELS_PER_CHAR - 1 - xp;  // column within relivant character cell (0 on the right)
 | 
			
		
	
		
			
				
					|  |  |  |  |     yp = y - r * ULTRA_Y_PIXELS_PER_CHAR; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.x_pixel_mask   = 0x01 << xp; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.x_pixel_offset = xp; | 
			
		
	
		
			
				
					|  |  |  |  |     ret_val.y_pixel_offset = yp; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     return ret_val; | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // AUTO_BED_LEVELING_UBL
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // ULTIPANEL
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | #endif // ULTRALCD_IMPL_HD44780_H
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |