diff --git a/Marlin/G26_Mesh_Validation_Tool.cpp b/Marlin/G26_Mesh_Validation_Tool.cpp index 80f6782aa4..a0e17fe76f 100644 --- a/Marlin/G26_Mesh_Validation_Tool.cpp +++ b/Marlin/G26_Mesh_Validation_Tool.cpp @@ -58,67 +58,67 @@ * * G26 is a Mesh Validation Tool intended to provide support for the Marlin Unified Bed Leveling System. * In order to fully utilize and benefit from the Marlin Unified Bed Leveling System an accurate Mesh must - * be defined. G29 is designed to allow the user to quickly validate the correctness of her Mesh. It will + * be defined. G29 is designed to allow the user to quickly validate the correctness of her Mesh. It will * first heat the bed and nozzle. It will then print lines and circles along the Mesh Cell boundaries and * the intersections of those lines (respectively). * * This action allows the user to immediately see where the Mesh is properly defined and where it needs to - * be edited. The command will generate the Mesh lines closest to the nozzle's starting position. Alternatively - * the user can specify the X and Y position of interest with command parameters. This allows the user to + * be edited. The command will generate the Mesh lines closest to the nozzle's starting position. Alternatively + * the user can specify the X and Y position of interest with command parameters. This allows the user to * focus on a particular area of the Mesh where attention is needed. * - * B # Bed Set the Bed Temperature. If not specified, a default of 60 C. will be assumed. + * B # Bed Set the Bed Temperature. If not specified, a default of 60 C. will be assumed. * * C Current When searching for Mesh Intersection points to draw, use the current nozzle location * as the base for any distance comparison. * - * D Disable Disable the Unified Bed Leveling System. In the normal case the user is invoking this - * command to see how well a Mesh as been adjusted to match a print surface. In order to do - * this the Unified Bed Leveling System is turned on by the G26 command. The D parameter + * D Disable Disable the Unified Bed Leveling System. In the normal case the user is invoking this + * command to see how well a Mesh as been adjusted to match a print surface. In order to do + * this the Unified Bed Leveling System is turned on by the G26 command. The D parameter * alters the command's normal behaviour and disables the Unified Bed Leveling System even if * it is on. * - * H # Hotend Set the Nozzle Temperature. If not specified, a default of 205 C. will be assumed. + * H # Hotend Set the Nozzle Temperature. If not specified, a default of 205 C. will be assumed. * - * F # Filament Used to specify the diameter of the filament being used. If not specified - * 1.75mm filament is assumed. If you are not getting acceptable results by using the + * F # Filament Used to specify the diameter of the filament being used. If not specified + * 1.75mm filament is assumed. If you are not getting acceptable results by using the * 'correct' numbers, you can scale this number up or down a little bit to change the amount * of filament that is being extruded during the printing of the various lines on the bed. * * K Keep-On Keep the heaters turned on at the end of the command. * - * L # Layer Layer height. (Height of nozzle above bed) If not specified .20mm will be used. + * L # Layer Layer height. (Height of nozzle above bed) If not specified .20mm will be used. * - * O # Ooooze How much your nozzle will Ooooze filament while getting in position to print. This + * O # Ooooze How much your nozzle will Ooooze filament while getting in position to print. This * is over kill, but using this parameter will let you get the very first 'circle' perfect * so you have a trophy to peel off of the bed and hang up to show how perfectly you have your - * Mesh calibrated. If not specified, a filament length of .3mm is assumed. + * Mesh calibrated. If not specified, a filament length of .3mm is assumed. * - * P # Prime Prime the nozzle with specified length of filament. If this parameter is not - * given, no prime action will take place. If the parameter specifies an amount, that much - * will be purged before continuing. If no amount is specified the command will start + * P # Prime Prime the nozzle with specified length of filament. If this parameter is not + * given, no prime action will take place. If the parameter specifies an amount, that much + * will be purged before continuing. If no amount is specified the command will start * purging filament until the user provides an LCD Click and then it will continue with - * printing the Mesh. You can carefully remove the spent filament with a needle nose - * pliers while holding the LCD Click wheel in a depressed state. If you do not have + * printing the Mesh. You can carefully remove the spent filament with a needle nose + * pliers while holding the LCD Click wheel in a depressed state. If you do not have * an LCD, you must specify a value if you use P. * - * Q # Multiplier Retraction Multiplier. Normally not needed. Retraction defaults to 1.0mm and + * Q # Multiplier Retraction Multiplier. Normally not needed. Retraction defaults to 1.0mm and * un-retraction is at 1.2mm These numbers will be scaled by the specified amount * * R # Repeat Prints the number of patterns given as a parameter, starting at the current location. * If a parameter isn't given, every point will be printed unless G26 is interrupted. * This works the same way that the UBL G29 P4 R parameter works. * - * NOTE: If you do not have an LCD, you -must- specify R. This is to ensure that you are + * NOTE: If you do not have an LCD, you -must- specify R. This is to ensure that you are * aware that there's some risk associated with printing without the ability to abort in - * cases where mesh point Z value may be inaccurate. As above, if you do not include a + * cases where mesh point Z value may be inaccurate. As above, if you do not include a * parameter, every point will be printed. * - * S # Nozzle Used to control the size of nozzle diameter. If not specified, a .4mm nozzle is assumed. + * S # Nozzle Used to control the size of nozzle diameter. If not specified, a .4mm nozzle is assumed. * - * U # Random Randomize the order that the circles are drawn on the bed. The search for the closest - * undrawn cicle is still done. But the distance to the location for each circle has a - * random number of the size specified added to it. Specifying S50 will give an interesting + * U # Random Randomize the order that the circles are drawn on the bed. The search for the closest + * undrawn cicle is still done. But the distance to the location for each circle has a + * random number of the size specified added to it. Specifying S50 will give an interesting * deviation from the normal behaviour on a 10 x 10 Mesh. * * X # X Coord. Specify the starting location of the drawing activity. @@ -218,7 +218,7 @@ * nozzle in a problem area and doing a G29 P4 R command. */ void unified_bed_leveling::G26() { - SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s)."); + SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s)."); float tmp, start_angle, end_angle; int i, xi, yi; mesh_index_pair location; @@ -264,7 +264,7 @@ //debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern.")); /** - * Declare and generate a sin() & cos() table to be used during the circle drawing. This will lighten + * Declare and generate a sin() & cos() table to be used during the circle drawing. This will lighten * the CPU load and make the arc drawing faster and more smooth */ float sin_table[360 / 30 + 1], cos_table[360 / 30 + 1]; @@ -575,17 +575,17 @@ /** * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one - * to the other. But there are really three sets of coordinates involved. The first coordinate - * is the present location of the nozzle. We don't necessarily want to print from this location. - * We first need to move the nozzle to the start of line segment where we want to print. Once + * to the other. But there are really three sets of coordinates involved. The first coordinate + * is the present location of the nozzle. We don't necessarily want to print from this location. + * We first need to move the nozzle to the start of line segment where we want to print. Once * there, we can use the two coordinates supplied to draw the line. * * Note: Although we assume the first set of coordinates is the start of the line and the second - * set of coordinates is the end of the line, it does not always work out that way. This function - * optimizes the movement to minimize the travel distance before it can start printing. This saves - * a lot of time and eleminates a lot of non-sensical movement of the nozzle. However, it does + * set of coordinates is the end of the line, it does not always work out that way. This function + * optimizes the movement to minimize the travel distance before it can start printing. This saves + * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does * cause a lot of very little short retracement of th nozzle when it draws the very first line - * segment of a 'circle'. The time this requires is very short and is easily saved by the other + * segment of a 'circle'. The time this requires is very short and is easily saved by the other * cases where the optimization comes into play. */ void unified_bed_leveling::print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) { @@ -850,7 +850,7 @@ stepper.synchronize(); // Without this synchronize, the purge is more consistent, // but because the planner has a buffer, we won't be able - // to stop as quickly. So we put up with the less smooth + // to stop as quickly. So we put up with the less smooth // action to give the user a more responsive 'Stop'. set_destination_to_current(); idle(); @@ -860,7 +860,7 @@ #if ENABLED(ULTRA_LCD) strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue; - // So... We cheat to get a message up. + // So... We cheat to get a message up. lcd_setstatusPGM(PSTR("Done Priming"), 99); lcd_quick_feedback(); #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index d244b198de..cbd33480a4 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3242,7 +3242,7 @@ inline void gcode_G0_G1( if (autoretract_enabled && !(parser.seen('X') || parser.seen('Y') || parser.seen('Z')) && parser.seen('E')) { const float echange = destination[E_AXIS] - current_position[E_AXIS]; // Is this move an attempt to retract or recover? - if ((echange < -MIN_RETRACT && !retracted[active_extruder]) || (echange > MIN_RETRACT && retracted[active_extruder])) { + if ((echange < -(MIN_RETRACT) && !retracted[active_extruder]) || (echange > MIN_RETRACT && retracted[active_extruder])) { current_position[E_AXIS] = destination[E_AXIS]; // hide the slicer-generated retract/recover from calculations sync_plan_position_e(); // AND from the planner retract(!retracted[active_extruder]); @@ -4617,11 +4617,11 @@ void home_all_axes() { gcode_G28(true); } #if ENABLED(AUTO_BED_LEVELING_LINEAR) -// mean += measured_z; // I believe this is unused code? -// eqnBVector[abl_probe_index] = measured_z; // I believe this is unused code? -// eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe; // I believe this is unused code? -// eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe; // I believe this is unused code? -// eqnAMatrix[abl_probe_index + 2 * abl2] = 1; // I believe this is unused code? + mean += measured_z; + eqnBVector[abl_probe_index] = measured_z; + eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe; + eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe; + eqnAMatrix[abl_probe_index + 2 * abl2] = 1; #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) @@ -4797,9 +4797,6 @@ void home_all_axes() { gcode_G28(true); } incremental_LSF(&lsf_results, xProbe, yProbe, measured_z); - #if ENABLED(AUTO_BED_LEVELING_LINEAR) - indexIntoAB[xCount][yCount] = abl_probe_index; - #endif #elif ENABLED(AUTO_BED_LEVELING_BILINEAR) z_values[xCount][yCount] = measured_z + zoffset; @@ -4924,11 +4921,10 @@ void home_all_axes() { gcode_G28(true); } } // Create the matrix but don't correct the position yet - if (!dryrun) { + if (!dryrun) planner.bed_level_matrix = matrix_3x3::create_look_at( - vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1) // We can eleminate the '-' here and up above + vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1) // We can eliminate the '-' here and up above ); - } // Show the Topography map if enabled if (do_topography_map) { diff --git a/Marlin/least_squares_fit.cpp b/Marlin/least_squares_fit.cpp index f8c7a0b521..66821ce58f 100644 --- a/Marlin/least_squares_fit.cpp +++ b/Marlin/least_squares_fit.cpp @@ -68,4 +68,4 @@ int finish_incremental_LSF(struct linear_fit_data *lsf) { return 0; } -#endif // AUTO_BED_LEVELING_UBL || ENABLED(AUTO_BED_LEVELING_LINEAR) +#endif // AUTO_BED_LEVELING_UBL || ENABLED(AUTO_BED_LEVELING_LINEAR) diff --git a/Marlin/least_squares_fit.h b/Marlin/least_squares_fit.h index 00d7a24191..9ed923ab49 100644 --- a/Marlin/least_squares_fit.h +++ b/Marlin/least_squares_fit.h @@ -34,7 +34,7 @@ #include "MarlinConfig.h" -#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(AUTO_BED_LEVELING_LINEAR) +#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(AUTO_BED_LEVELING_LINEAR) #include "Marlin.h" #include "macros.h" diff --git a/Marlin/ultralcd_impl_DOGM.h b/Marlin/ultralcd_impl_DOGM.h index 28848cdebe..5d075124da 100644 --- a/Marlin/ultralcd_impl_DOGM.h +++ b/Marlin/ultralcd_impl_DOGM.h @@ -976,8 +976,8 @@ static void lcd_implementation_status_screen() { uint8_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X), y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (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), + pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X), + pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y), x_offset = MAP_UPPER_LEFT_CORNER_X + 1 + (MAP_MAX_PIXELS_X - x_map_pixels - 2) / 2, y_offset = MAP_UPPER_LEFT_CORNER_Y + 1 + (MAP_MAX_PIXELS_Y - y_map_pixels - 2) / 2; @@ -996,11 +996,11 @@ static void lcd_implementation_status_screen() { // Display Mesh Point Locations u8g.setColorIndex(1); - const uint8_t sx = x_offset + pixels_per_X_mesh_pnt / 2; - uint8_t y = y_offset + pixels_per_Y_mesh_pnt / 2; - for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++, y += pixels_per_Y_mesh_pnt) + const uint8_t sx = x_offset + pixels_per_x_mesh_pnt / 2; + uint8_t y = y_offset + pixels_per_y_mesh_pnt / 2; + for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++, y += pixels_per_y_mesh_pnt) if (PAGE_CONTAINS(y, y)) - for (uint8_t i = 0, x = sx; i < GRID_MAX_POINTS_X; i++, x += pixels_per_X_mesh_pnt) + for (uint8_t i = 0, x = sx; i < GRID_MAX_POINTS_X; i++, x += pixels_per_x_mesh_pnt) u8g.drawBox(sx, y, 1, 1); // Fill in the Specified Mesh Point @@ -1008,11 +1008,11 @@ static void lcd_implementation_status_screen() { uint8_t inverted_y = GRID_MAX_POINTS_Y - y_plot - 1; // The origin is typically in the lower right corner. We need to // invert the Y to get it to plot in the right location. - const uint8_t by = y_offset + inverted_y * pixels_per_Y_mesh_pnt; - if (PAGE_CONTAINS(by, by + pixels_per_Y_mesh_pnt)) + const uint8_t by = y_offset + inverted_y * pixels_per_y_mesh_pnt; + if (PAGE_CONTAINS(by, by + pixels_per_y_mesh_pnt)) u8g.drawBox( - x_offset + x_plot * pixels_per_X_mesh_pnt, by, - pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt + x_offset + x_plot * pixels_per_x_mesh_pnt, by, + pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt ); // Put Relevant Text on Display diff --git a/Marlin/ultralcd_impl_HD44780.h b/Marlin/ultralcd_impl_HD44780.h index 7c530d445a..e8ecd9cf4f 100644 --- a/Marlin/ultralcd_impl_HD44780.h +++ b/Marlin/ultralcd_impl_HD44780.h @@ -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,345 +1057,351 @@ 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 + static uint8_t ledsprev = 0; + uint8_t leds = 0; - static void lcd_implementation_update_indicators() { - // Set the LEDS - referred to as backlights by the LiquidTWI2 library - static uint8_t ledsprev = 0; - uint8_t leds = 0; + if (thermalManager.degTargetBed() > 0) leds |= LED_A; - if (thermalManager.degTargetBed() > 0) leds |= LED_A; + if (thermalManager.degTargetHotend(0) > 0) leds |= LED_B; - if (thermalManager.degTargetHotend(0) > 0) leds |= LED_B; + #if FAN_COUNT > 0 + if (0 + #if HAS_FAN0 + || fanSpeeds[0] + #endif + #if HAS_FAN1 + || fanSpeeds[1] + #endif + #if HAS_FAN2 + || fanSpeeds[2] + #endif + ) leds |= LED_C; + #endif // FAN_COUNT > 0 - #if FAN_COUNT > 0 - if (0 - #if HAS_FAN0 - || fanSpeeds[0] - #endif - #if HAS_FAN1 - || fanSpeeds[1] - #endif - #if HAS_FAN2 - || fanSpeeds[2] - #endif - ) leds |= LED_C; - #endif // FAN_COUNT > 0 + #if HOTENDS > 1 + if (thermalManager.degTargetHotend(1) > 0) leds |= LED_C; + #endif - #if HOTENDS > 1 - if (thermalManager.degTargetHotend(1) > 0) leds |= LED_C; - #endif - - if (leds != ledsprev) { - lcd.setBacklight(leds); - ledsprev = leds; + if (leds != ledsprev) { + lcd.setBacklight(leds); + ledsprev = leds; + } } - } -#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: + /** + Possible map screens: - 16x2 |X000.00 Y000.00| - |(00,00) Z00.000| + 16x2 |X000.00 Y000.00| + |(00,00) Z00.000| - 20x2 | X:000.00 Y:000.00 | - | (00,00) Z:00.000 | + 20x2 | X:000.00 Y:000.00 | + | (00,00) Z:00.000 | - 16x4 |+-------+(00,00)| - || |X000.00| - || |Y000.00| - |+-------+Z00.000| + 16x4 |+-------+(00,00)| + || |X000.00| + || |Y000.00| + |+-------+Z00.000| - 20x4 | +-------+ (00,00) | - | | | X:000.00| - | | | Y:000.00| - | +-------+ Z:00.000| + 20x4 | +-------+ (00,00) | + | | | X:000.00| + | | | Y:000.00| + | +-------+ Z:00.000| */ - struct custom_char { - uint8_t custom_char_bits[ULTRA_Y_PIXELS_PER_CHAR]; - }; + typedef struct { + uint8_t custom_char_bits[ULTRA_Y_PIXELS_PER_CHAR]; + } custom_char; - struct coordinate pixel_location(uint8_t x, uint8_t y); + typedef struct { + uint8_t column, row; + uint8_t y_pixel_offset, x_pixel_offset; + uint8_t x_pixel_mask; + } coordinate; - struct coordinate { - uint8_t column; - uint8_t row; - uint8_t y_pixel_offset; - uint8_t x_pixel_offset; - uint8_t x_pixel_mask; - }; + 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 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 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"); - } - */ + //*/ - void lcd_implementation_ubl_plot(uint8_t x, uint8_t inverted_y) { + coordinate pixel_location(int16_t x, int16_t y) { + coordinate ret_val; + int16_t xp, yp, r, c; - #if LCD_WIDTH >= 20 - #define _LCD_W_POS 12 - #define _PLOT_X 1 - #define _MAP_X 3 - #define _LABEL(C,X,Y) lcd.setCursor(X, Y); lcd.print(C) - #define _XLABEL(X,Y) _LABEL("X:",X,Y) - #define _YLABEL(X,Y) _LABEL("Y:",X,Y) - #define _ZLABEL(X,Y) _LABEL("Z:",X,Y) - #else - #define _LCD_W_POS 8 - #define _PLOT_X 0 - #define _MAP_X 1 - #define _LABEL(X,Y,C) lcd.setCursor(X, Y); lcd.write(C) - #define _XLABEL(X,Y) _LABEL('X',X,Y) - #define _YLABEL(X,Y) _LABEL('Y',X,Y) - #define _ZLABEL(X,Y) _LABEL('Z',X,Y) - #endif + x++; y++; // +1 because lines on the left and top - #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display + c = x / (ULTRA_X_PIXELS_PER_CHAR); + r = y / (ULTRA_Y_PIXELS_PER_CHAR); - /** - * Show X and Y positions - */ - _XLABEL(_PLOT_X, 0); - lcd.print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x])))); + ret_val.column = c; + ret_val.row = r; - _YLABEL(_LCD_W_POS, 0); - lcd.print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y])))); + 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); - lcd.setCursor(_PLOT_X, 0); + ret_val.x_pixel_mask = _BV(xp); + ret_val.x_pixel_offset = xp; + ret_val.y_pixel_offset = yp; + return ret_val; + } - #else // 16x4 or 20x4 display + coordinate pixel_location(uint8_t x, uint8_t y) { return pixel_location((int16_t)x, (int16_t)y); } - 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; + void lcd_implementation_ubl_plot(uint8_t x, uint8_t inverted_y) { - // ******************************************************** - // ************ Clear and setup everything ********* - // ******************************************************** + #if LCD_WIDTH >= 20 + #define _LCD_W_POS 12 + #define _PLOT_X 1 + #define _MAP_X 3 + #define _LABEL(C,X,Y) lcd.setCursor(X, Y); lcd.print(C) + #define _XLABEL(X,Y) _LABEL("X:",X,Y) + #define _YLABEL(X,Y) _LABEL("Y:",X,Y) + #define _ZLABEL(X,Y) _LABEL("Z:",X,Y) + #else + #define _LCD_W_POS 8 + #define _PLOT_X 0 + #define _MAP_X 1 + #define _LABEL(X,Y,C) lcd.setCursor(X, Y); lcd.write(C) + #define _XLABEL(X,Y) _LABEL('X',X,Y) + #define _YLABEL(X,Y) _LABEL('Y',X,Y) + #define _ZLABEL(X,Y) _LABEL('Z',X,Y) + #endif - y = GRID_MAX_POINTS_Y - inverted_y - 1; + #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display - upper_left.column = 0; - upper_left.row = 0; - lower_right.column = 0; - lower_right.row = 0; + /** + * Show X and Y positions + */ + _XLABEL(_PLOT_X, 0); + lcd.print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x])))); - lcd_implementation_clear(); + _YLABEL(_LCD_W_POS, 0); + lcd.print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y])))); - 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; + lcd.setCursor(_PLOT_X, 0); - pixels_per_X_mesh_pnt = x_map_pixels / GRID_MAX_POINTS_X; - pixels_per_Y_mesh_pnt = y_map_pixels / GRID_MAX_POINTS_Y; + #else // 16x4 or 20x4 display - 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. - } + 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; - 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. - } + y = GRID_MAX_POINTS_Y - inverted_y - 1; - 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 + upper_left.column = 0; + upper_left.row = 0; + lower_right.column = 0; + lower_right.row = 0; - 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 + lcd_implementation_clear(); - n_rows = (bottom_line / ULTRA_Y_PIXELS_PER_CHAR) + 1; - n_cols = (right_edge / ULTRA_X_PIXELS_PER_CHAR) + 1; + 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; - for (i = 0; i < n_cols; i++) { - lcd.setCursor(i, 0); - lcd.print((char) 0x00); // top line of the box + pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X); + pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y); - 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.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 */ - // - - 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 - lcd.write(' '); - 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); - 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); - 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); - - 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) - 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); - - 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; - 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. - */ - - //dump_custom_char("at entry:", &new_char); - - CLEAR_CUSTOM_CHAR(&new_char); - for(j=upper_left.y_pixel_offset; j= ULTRA_Y_PIXELS_PER_CHAR) - break; - i=upper_left.x_pixel_mask; - for(k=0; k> 1; + 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. } - } - //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); + 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. + } - lcd.setCursor(upper_left.column, upper_left.row); - lcd.write(0x04); - //dump_custom_char("after lcd update:", &new_char); + 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 - /* - * 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) { - 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 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.write(' '); + } + + 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 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); + for (j = 0; j < ULTRA_Y_PIXELS_PER_CHAR; j++) + 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 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] = (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; + 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; + 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. + */ + + //dump_custom_char("at entry:", &new_char); + + 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; } } - add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, TOP_RIGHT); + //dump_custom_char("after loops:", &new_char); - lcd.createChar(5, (uint8_t *) &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.setCursor(lower_right.column, upper_left.row); - lcd.write(0x05); - } + lcd.setCursor(upper_left.column, upper_left.row); + lcd.write(0x04); + //dump_custom_char("after lcd update:", &new_char); - /* - * 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> 1; - if (!i) - break; - } - } - add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, LOWER_LEFT); - lcd.createChar(6, (uint8_t *) &new_char); - - lcd.setCursor(upper_left.column, lower_right.row); - 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> 1; + 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 >>= 1; + } } + add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, TOP_RIGHT); + + lcd.createChar(5, (uint8_t *) &new_char); + + lcd.setCursor(lower_right.column, upper_left.row); + lcd.write(0x05); } - add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, LOWER_RIGHT); - lcd.createChar(7, (uint8_t *) &new_char); - lcd.setCursor(lower_right.column, lower_right.row); - lcd.write(0x07); - } + /** + * Next, check for two character cells stacked on top of each other being used to display the Mesh Point + */ + 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; + if (!(i >>= 1)) break; + } + } + add_edges_to_custom_char(&new_char, &upper_left, &lower_right, &bottom_right_corner, LOWER_LEFT); + lcd.createChar(6, (uint8_t *) &new_char); - #endif + lcd.setCursor(upper_left.column, lower_right.row); + 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 == 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 = _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 >>= 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.setCursor(lower_right.column, lower_right.row); + lcd.write(0x07); + } + + #endif /** * Print plot position @@ -1407,209 +1413,123 @@ static void lcd_implementation_status_screen() { lcd.print(inverted_y); lcd.write(')'); - #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display + #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display + + /** + * Print Z values + */ + _ZLABEL(_LCD_W_POS, 1); + if (!isnan(ubl.z_values[x][inverted_y])) + lcd.print(ftostr43sign(ubl.z_values[x][inverted_y])); + else + lcd_printPGM(PSTR(" -----")); + + #else // 16x4 or 20x4 display + + /** + * Show all values at right of screen + */ + _XLABEL(_LCD_W_POS, 1); + lcd.print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x])))); + _YLABEL(_LCD_W_POS, 2); + lcd.print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y])))); + + /** + * Show the location value + */ + _ZLABEL(_LCD_W_POS, 3); + if (!isnan(ubl.z_values[x][inverted_y])) + lcd.print(ftostr43sign(ubl.z_values[x][inverted_y])); + else + lcd_printPGM(PSTR(" -----")); + + #endif // LCD_HEIGHT > 3 + } + + 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; /** - * Print Z values + * Check if Top line of box needs to be filled in */ - _ZLABEL(_LCD_W_POS, 1); - if (!isnan(ubl.z_values[x][inverted_y])) - lcd.print(ftostr43sign(ubl.z_values[x][inverted_y])); - else - lcd_printPGM(PSTR(" -----")); + if (ul->row == 0 && ((cell_location & TOP_LEFT) || (cell_location & TOP_RIGHT))) { // Only fill in the top line for the top character cells - #else // 16x4 or 20x4 display - - /** - * Show all values at right of screen - */ - _XLABEL(_LCD_W_POS, 1); - lcd.print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x])))); - _YLABEL(_LCD_W_POS, 2); - lcd.print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y])))); - - /** - * Show the location value - */ - _ZLABEL(_LCD_W_POS, 3); - if (!isnan(ubl.z_values[x][inverted_y])) - lcd.print(ftostr43sign(ubl.z_values[x][inverted_y])); - else - 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; - 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 (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; icustom_char_bits[0] |= 0x01 << i; - } - } - else { - if (cell_location & TOP_LEFT) - custom->custom_char_bits[0] = 0xff; // multiple column in the 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; icustom_char_bits[0] |= 0x01 << i; + 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 + 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 + 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++) + 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) */ && 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 < _BV(ULTRA_X_PIXELS_PER_CHAR)) { + custom->custom_char_bits[brc->y_pixel_offset] |= k; + 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) && 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; + while (k < _BV(ULTRA_X_PIXELS_PER_CHAR)) { + custom->custom_char_bits[brc->y_pixel_offset] |= k; + k <<= 1; + } + } + + /** + * Check if right line of box needs to be filled in + */ + // 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; + } + } } - } - /* - * 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; + #endif // AUTO_BED_LEVELING_UBL - for (i = 0; i < k; i++) - custom->custom_char_bits[i] |= 0x01 << (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 - k = 0x01; - } - while (k < (0x01 << ULTRA_X_PIXELS_PER_CHAR)) { - custom->custom_char_bits[brc->y_pixel_offset] |= k; - k = 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) - 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)) { - custom->custom_char_bits[brc->y_pixel_offset] |= k; - k = 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; - } - } - } - - 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 - - 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