body { font-family: Arial, sans-serif; margin: 20px; position: relative; display: flex; justify-content: flex-start; align-items: flex-start; padding-left: 50px; padding-right: 50px; } .container { max-width: 320px; padding: 20px; border: 1px solid #ccc; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); margin-right: 20px; height: 320px; flex-shrink: 0; flex-grow: 0; margin-top: 20px; margin-left: 100px; } .main-container { display: flex; margin-left: 5px; } input[type="number"] { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-radius: 5px; } button { width: 100%; padding: 10px; background-color: #007BFF; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #0056b3; } .result { flex-shrink: 0; margin-top: 10px; padding: 10px; border-radius: 5px; margin-left: 10px; } table { width: 100%; border-collapse: collapse; } th, td { border: 1px solid #ddd; padding: 8px; } #tireCanvas { border: none; border-radius: 5px; margin-top: 20px; margin-left: 80px; } .unit-buttons { display: flex; justify-content: space-between; margin-top: 20px; } .unit-buttons button { width: calc(50% - 20px); padding: 10px; background-color: #ccc; color: #000; border: none; border-radius: 5px; cursor: pointer; } .unit-buttons button:hover { background-color: #b3b3b3; }
Search
Close this search box.

Home

How to Update Flash ESP8266 Firmware – Flashing Official AT Firmware

This is the second project on ESP8266 and in this project, I’ll show you how to flash the Official Espressif Firmware in ESP8266 using Arduino. This project can also be used if you want to update to the latest ESP8266 Firmware.

In the previous ESP8266 Project, we have seen how to write our own program in ESP8266 using Arduino IDE and control an LED using the GPIO Pins. In the same project, I’ve mentioned that by default, the ESP8266 ESP-01 Module comes with an AT Command Firmware.

But if we write our own program to access the GPIO Pins (like we did in the previous project), the existing firmware will be completely erased and the new program will be written.

Even though ESP8266 WiFi Module is manufactured by Espressif Systems, the SoC is used by many third party manufacturers to implement their own custom modules. In my case, I have the ESP8266 ESP-01 Module by AI-Thinker.

This leads to a lot of questions like whether the firmware is original or not, is the firmware up to date or not and many other.

Flash ESP8266 Firmware Image 12

So, in this project, we will flash the official Espressif Systems’ firmware for ESP8266 Module using the official ESP8266 Flasher Tool provided by Espressif Systems which is the ESP8266 FLASH DOWNLOAD TOOL and Arduino UNO as the USB to Serial Interface.

The ESP8266 Firmware can be installed for two reasons: If you want to update the ESP8266 Firmware to its latest version or to completely install the new firmware (in case it was overwritten by any program). So, let’s get started.

How to Update Flash ESP8266 Firmware

Hardware Setup for ESP8266 Firmware Update

Before proceeding into the process of updating the ESP8266 SoC’s Firmware, it is important to configure the ESP8266 WiFi Module in Download Mode or Programming Mode.

If you remember in the GETTING STARTED WITH ESP8266 AND ARDUINO project, I’ve mentioned that GPIO0 and RST Pins of the ESP8266 Module play an important role in configuring it in Download Mode.

We will implement the same setup here as well. So, the connections are as follows.

  • VCC to 3.3V
  • GND to GND
  • TX to TX of Arduino UNO
  • RX to RX of Arduino UNO (through level converter)
  • GPIO0 to GND
  • RST to GND through Push Button
  • CH_PD to 3.3V

Circuit Diagram for Flashing the Firmware to ESP8266

The following image shows the circuit diagram for enabling the Flashing Mode in ESP8266. In order to put the ESP8266 SoC in Flashing Mode, the GPIO0 Pin must be connected to GND and a momentary GND Pulse on RST Pin.

Flash ESP8266 Firmware Image 11

Components Required

  • Arduino UNO         
  • ESP8266 ESP-01 (any ESP8266 Module)
  • 1 KΩ Resistor
  • 2.2 KΩ Resistor
  • Push Button
  • SPDT Switch
  • Connecting Wires
  • Mini Breadboard

IMPORTANT NOTES

  • Before proceeding further, please refer the previous project for configuring Arduino IDE and getting the Arduino UNO ready for flashing the firmware.
  • I’ve connected the GPIO0 Pin to GND directly. And after flashing the Firmware, I’ve disconnected it from GND. You can use a SPDT switch to achieve this action i.e. in one position, the GPIO0 is connected to GND and in the other position, it is free to use as a GPIO.
  • ESP8266 can’t tolerate 5V. It must be connected to 3.3V. Even the RX Pin of ESP8266 is connected through a level converter.

Checking the Current Firmware Version

Before installing the Firmware, we will first check the existing firmware in the ESP8266 Module using serial communication. For this, we need to disconnect the GPIO0 pin from GND. *IMPORTANT*.  

After making the connections as per the circuit diagram given above (and disconnecting the GPIO0 from GND), plug-in the USB Cable of Arduino to the Computer and Open any Serial Monitor Software. I am using the Arduino’s Serial Monitor. You can use any software like Putty, Terminal, etc.

In Arduino IDE, select the correct COM Port and open the Serial Monitor. Set the baud rate to 115200 and select Both NL and CR option in the serial monitor. After this press the RST Button of the ESP8266 for a second and release. The ESP8266 Module will reset and display “ready” after some garbage data on the serial monitor.

Flash ESP8266 Firmware Image 1

In order to check for the firmware version, you need to type the following AT Command and hit send. This command will return the firmware version of the ESP8266 Module. All the AT Commands should be in Upper Case.

AT+GMR

Flash ESP8266 Firmware Image 2

If you notice, my firmware is by Ai-Thinker Technology, the manufacturer of my ESP8266 ESP-01 Module and it is pretty old one. The AT Command Set Version is 0.21.0.0 and the SDK Version is 0.9.5.  

I will now replace this firmware with the Espressif Firmware (the manufacturer of ESP8266 SoC).

NOTE: Make sure that GPIO0 Pin connected to GND before proceeding further.

Downloading the Latest ESP8266 Firmware

There are two types of SDK or Software Development Kits for ESP8266: Non-OS SDK and RTOS SDK. The Non-OS SDK, as the name suggests, isn’t based on any OS. Using this SDK, you can compile IOT_Demo and AT Commands. The RTOS SDK on the other hand is based on FreeRTOS.

I’ll be using the Non-OS SDK (well, technically, the Firmware files based on the Non-OS SDK). The ESP8266 Firmware files are in the form of Binary Files i.e. .bin files.

Now since I will be using only the AT Command Set of the ESP8266, I will download only the Bin Files associated with the AT Commands. In order to download the AT Commands Firmware for ESP8266, visit the official link here or directly download from this link.

Flash ESP8266 Firmware Image 3

There are other firmware versions for ESP8266 Module. Try the procedure mentioned in this project first and if you succeed, you can try installing other ESP8266 Firmware. Other firmware can be downloaded from the SDK section in the link mentioned above.

Downloading the ESP8266 Flash Download Tool

The next step is to download the Tool to update the Firmware of ESP8266. Espressif Systems developed a small software just for this purpose. It is called the ESP Flash Download Tool.

In order to download the ESP8266 Firmware Flash Download Tool, visit this link and in the Tools section, download the ESP Flash Download Tools or you can directly download from this link.

Flash ESP8266 Firmware Image 4

Now that we have downloaded the Firmware and the Flasher Tool for ESP8266, we will proceed with installing the Firmware in ESP8266.   

Installing the Firmware in ESP8266

In order to flash the firmware in ESP8266, first open the Flash Download Tool or the Flasher Software of ESP8266. At the time of working on this project, I have the version 3.6.2.2. So, open the application file ESPFlashDownloadTool_v3.6.2.2.

You will then get various options like ESP8266 Download Tool, ESP8285 Download Tool, ESP32 Download Tool and ESP32D2WD Download Tool. Select the ESP8266 Download Tool.

Flash ESP8266 Firmware Image 5

After opening the ESP8266 Flash Download Tool, you need to select the firmware files that we need to install. You need to upload four files at four different addresses. The following table will give you the list of files and their corresponding addresses.

NOTE: This list is for Firmware over the Air (FOTA) Flash Memory Mapping for ESP8266 Modules with 1MB of Flash. For other flash sizes, please refer to the ESP8266 Getting Started Guide, from this link.

File

Address in Flash Memory

boot_v1.7.bin

0x00000

user1.1024.new.2.bin

0x10000

esp_init_data_default.bin

0xFC000

blank.bin

0xFE000

In the ESP8266 Download Tool, in the SPI Download Tab, select the necessary files in the “Download Path Config” option by click on the (…) button. Also, add the corresponding addresses in the space provided.

Flash ESP8266 Firmware Image 6

After selecting the four files and filling in the Addresses, set the crystal frequency to 26MHz (it is usually 26MHz but in case your ESP8266 board has a different crystal, enter that value). Next select the flash size. Since I have a 1MB flash on-board, I have selected the 8Mbit (which is equal to 1MB) flash size option.

Finally, select the correct COM Port and set the baud rate to 115200. Make sure that all the serial terminal are closed.

Before starting the flashing, check that GPIO0 is connected to GND and give a pulse LOW (push the Reset button) on the RST pin.

Now click on START button. The flashing of the firmware in ESP8266 should begin. If you notice in the ESP8266 Firmware Flash Tool, the moment you click on START, you will get two MAC Address as AP and STA and also information about the Module in the DETECTED INFO section.

Flash ESP8266 Firmware Image 7

If everything goes well, the ESP8266 Module must be updated with new firmware. If there is any error, disconnect the USB cable, connect it once again, and after clicking on START, push the Reset button of the ESP8266.

You will get a FINISH message on the Tool and you can close the tool after this. Disconnect the GPIO0 from GND and reset the device. Open the serial monitor of Arduino once again and check for new firmware. 

Flash ESP8266 Firmware Image 8

NOTE: Click on Reset button after opening the serial monitor.

In order to check the firmware version, type AT+GMR and hit send. You will get a response with the AT Version number and the SDK Version number. In my case, the new AT Command Set Version is 1.5.0.0 and the SDK Version is 2.1.0.

Flash ESP8266 Firmware Image 9

In this project, you have seen how to update/flash firmware in ESP8266 Module using the official Espressif ESP8266 Firmware.    

21 Responses

  1. Hi ! I did follow the procedure and saw successful FINISH at the end. However after disconnecting GPIo and resetting the device, it gave some junk characters and was saying Wait for WIFI……….and goes on with dots ? It does not respond to AT calls from Serial Monitor (arduino). Please suggest….

  2. seem to be unable to do this. Downloading goes perfect but when I reset the ESP12 it says:
    ets Jan 8 2013,rst cause:2, boot mode:(3,6)

    load 0x40100000, len 2592, room 16
    tail 0
    chksum 0xf3
    load 0x3ffe8000, len 764, room 8
    tail 4
    chksum 0x92
    load 0x3ffe82fc, len 676, room 4
    tail 0
    chksum 0x22
    csum 0x22

    2nd boot version : 1.7(5d6f877)
    SPI Speed : 40MHz
    SPI Mode : QIO
    SPI Flash Size & Map: 4Mbit(256KB+256KB)
    jump to run user2 @ 41000

    error magic!
    backup boot failed.

    user code done

    What’s going on? Is there a different BIN for ESP12?

    1. No. ESP-12 is also based on ESP8266EX SoC but with additional features like more GPIO Pins, ADC, SPI, I2C etc. I am not sure what is going on here.

      1. I had the exact same problem. Then I realized that the check boxes next to the “path” were unticked. Effectively saying “I don’t want to flash any of these files to the esp8266.” Tick the file selection boxes and all worked well.

  3. Thanjs for the info. However, after following your steps carefully I keep getting this error. ESP8266 Chip sync error esp_sync_blocking. Can you help please

  4. I followed this exact procedure twice, 1st time was trying to use v 1..6.2 firmware. I’m a little nervous about the load addresses??? This effectively bricked the first unit.
    I tried again, reading and following every step exactly but this time using the same v 1.5.1 firmware.
    And I got the same results… another bricked unit!

    Both units send output, the bit’s are scoped at 12.3uSec, which is about 80,000 baud (not a standard baud rate) My guess? There is something corrupt in the firmware or the load addresses are wrong?

    Can you please tell me how you found those load addresses?

    1. I have been using the same addresses since I have posted it here and had no problems what so ever. I even upgraded my ESP-01 to the newer firmware (V1.6.2) few days back using the same procedure.
      These addresses are provided in the official data sheet of ESP8266EX SoC (which can be downloaded from the Espressif website) and also few github pages.
      May I know what module are you using? Also, does it come with 5V to 3.3V level converters (for RX of ESP8266)? What about the power supply to the module (only 3.3V).

    2. There is a problem with the ESP8266 download tool. I did not explore what version it starts in, but under 3.6.4 the SPIDownload tab will not flash correctly and you’ll see jibberish when trying to use AT interface.

      Simple fix, use the MultiDownload tab, widen the window and just set and load a single module. It will load and behave correctly. This is not a problem with the above directions, the hardware or the firmware (1.6.2) it is a problem with the Download Tool.

  5. Hi, I am wondering if my ESP 8266 is brick.
    1) Initally I am able to talk with my ESP 8266 with AT command, but it is unstable sometime it accept my at command sometime not. But I pretty sure it was working.
    2) I tried to upload sketch via arduino UNO few time, some time it show EEPROM fail error message, but did success after a few try
    3) Now it didnt respond my at command and cannot detect tESP 8266 WiFi any more
    4) I tried to flash according to your tutorial. but WiFI and At command do not have respond.

    What should it do ?

  6. I have used the procedure to update the firmware on my ESP-01 module without success. Despite checking everything, when I start the flashing process everything hangs up and there is no indicator that the flashing process is going on. I am at a loss what to do now and wonder if anyone can offer suggestions.

  7. Hello. I also have problem trying to flash load. where appear something like : ESP8266 Chip efuse check error esp_check_mac_and_efuse. Whats is this and how can I solve.?
    Thanks.

  8. I hope this post will help someone with problems flashing the ESP modules: I had multiple unsuccessful attempts at flashing these units. It is somewhat of a nightmare.

    Before upgrading to a new SDK version, I downgrade my ESP module to an older version using this tool: Click Here

    Once the flasher tool updates the module with the older version, I then use the Espressif tools (together with the stated procedure) to upgrade to the latest SDK version. This seems to work for me. I can not offer any technical explanation why it would work, but it does.

    Hope it helps.

  9. I am going to tell my experience.
    1. If you have uploaded some Arduino codes before, you will not see “ready” after some garbage data. Don’t worry, skip that and follow next instructions.
    2. You can see what is the garbage data by switching the baud rate to 74880 baud then pushing reset button.
    3. This is that data on my ESP8266.

    ets Jan 8 2013,rst cause:2, boot mode:(3,6)

    load 0x40100000, len 2592, room 16
    tail 0
    chksum 0xf3
    load 0x3ffe8000, len 764, room 8
    tail 4
    chksum 0x92
    load 0x3ffe82fc, len 676, room 4
    tail 0
    chksum 0x22
    csum 0x22

    2nd boot version : 1.7(5d6f877)
    SPI Speed : 40MHz
    SPI Mode : QIO
    SPI Flash Size & Map: 8Mbit(512KB+512KB)
    jump to run user1 @ 1000

    rf cal sector: 251
    freq trace enable 1
    rf[112] : 03
    rf[113] : 00
    rf[114] : 01

    SDK ver: 2.1.0(ace2d95) compiled @ Oct 24 2017 12:04:16
    phy ver: 1134_0, pp ver: 10.2

    4. There is an error in “addresses on flash memories ” table. The address for user1.1024.new.2.bin file should be 0x01000 not 0x100000.

    1. thank you, giving the correct adresses outputs

      ets Jan 8 2013,rst cause:2, boot mode:(3,7)

      load 0x40100000, len 2592, room 16
      tail 0
      chksum 0xf3
      load 0x3ffe8000, len 764, room 8
      tail 4
      chksum 0x92
      load 0x3ffe82fc, len 676, room 4
      tail 0
      chksum 0x22
      csum 0x22

      2nd boot version : 1.7(5d6f877)
      SPI Speed : 40MHz
      SPI Mode : QIO
      SPI Flash Size & Map: 16Mbit(1024KB+1024KB)
      jump to run user1 @ 1000

      but no operation / AT cmd seems to work. How to proceed?

  10. Firmware flashed just fine to a ESP8266. Device reports ready in terminal. However it doesn’t respond to AT commands.

    Used AT firmware 1.7 from espressif

  11. After i successfully flashed the ESP it only outputs the garbage in the serial monitor. And it doesnt response ready.
    Anyone know anything?

  12. Firstly – thanks for a great guide, really helped me bring a non-responsive device back to life.

    Took me a while to find the right firmware but once I did I managed to flash my device to 1.5.1. (ESP8266 AT Bin V1.5.1)

    Interestingly the max version I seem to be able to upgrade to is 1.6.2 (ESP8266 AT Bin V1.6.2) using the same addresses as the guide. 1.7.1 transfers but the device is non-responsive. 1.6.2 seems to do the trick for what I needed.

    Regards

    Andrew

Leave a Reply

Your email address will not be published. Required fields are marked *

let currentUnit = 'inches'; // Default unit const MM_TO_INCHES = 0.0393701; // 1 millimeter = 0.0393701 inches function calculateTireSize() { let width = parseFloat(document.getElementById('width').value); let aspectRatio = parseFloat(document.getElementById('aspectRatio').value); let diameter = parseFloat(document.getElementById('diameter').value); if (isNaN(width) || isNaN(aspectRatio) || isNaN(diameter)) { alert('Please enter valid numbers for all fields.'); return; } let sidewallHeight = (width * aspectRatio) / 100; let sidewallHeightUnits = currentUnit === 'mm' ? sidewallHeight : sidewallHeight / MM_TO_INCHES; let overallDiameterMM = (2 * sidewallHeight) + (diameter * 25.4); let overallDiameter = currentUnit === 'mm' ? overallDiameterMM : overallDiameterMM / 25.4; let wheelSizeMM = diameter * 25.4; let wheelSize = currentUnit === 'mm' ? wheelSizeMM : diameter; let circumferenceMM = overallDiameterMM * Math.PI; let circumference = currentUnit === 'mm' ? circumferenceMM : circumferenceMM / 25.4; let revsPerMile = 63360 / circumference; let revsPerKm = 1000 / (circumferenceMM / 1000); let tireWidthUnits = currentUnit === 'mm' ? width : width / MM_TO_INCHES; document.getElementById('result').innerHTML = `
MeasurementValue (${currentUnit})
Sidewall Height${sidewallHeightUnits.toFixed(2)}
Overall Diameter${overallDiameter.toFixed(2)}
Wheel Size${wheelSize.toFixed(2)}
Width${tireWidthUnits.toFixed(2)}
Circumference${circumference.toFixed(2)}
Revolutions per Mile${revsPerMile.toFixed(2)}
Revolutions per Kilometer${revsPerKm.toFixed(2)}
`; drawTires(width, overallDiameterMM, aspectRatio, overallDiameter, sidewallHeight, wheelSize); } function setUnit(unit) { currentUnit = unit; calculateTireSize(); // Recalculate and redraw based on the new unit } function drawTires(width, overallDiameterMM, aspectRatio, overallDiameter, sidewallHeight, wheelSize) { var canvas = document.getElementById('tireCanvas'); var context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); let scaleFactor = Math.min(canvas.width, canvas.height) / (overallDiameterMM / 25.4 * 3); let frontDiameter = (overallDiameterMM / 25.4) * scaleFactor; let frontInnerDiameter = ((overallDiameterMM - (2 * (width * aspectRatio / 100))) / 25.4) * scaleFactor; let sideWidth = 100 * scaleFactor / 5; let sideDiameter = frontDiameter; let leftSpace = (canvas.width - (2 * frontDiameter + sideWidth + 50)) / 2 + 60; let topSpace = (canvas.height - frontDiameter) / 6; drawFrontTire(context, leftSpace, topSpace, frontDiameter, frontInnerDiameter, width); drawSideTire(context, leftSpace + frontDiameter + 50, topSpace, sideWidth, sideDiameter, width); drawVerticalLine(context, leftSpace + frontDiameter / 2, topSpace, frontDiameter, sideDiameter, overallDiameter); } function drawFrontTire(context, leftSpace, topSpace, diameter, innerDiameter, width) { var wallThickness = (diameter - innerDiameter) / 2; context.fillStyle = "#999"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, diameter / 2, 0, 2 * Math.PI); context.fill(); context.fillStyle = "#000"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, diameter / 2 - 1, 0, 2 * Math.PI); context.fill(); if (wallThickness > 10) { context.fillStyle = "#333"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, diameter / 2 - wallThickness / 2, 0, 2 * Math.PI); context.fill(); context.fillStyle = "#000"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, diameter / 2 - wallThickness / 2 - 1, 0, 2 * Math.PI); context.fill(); } context.fillStyle = "#ddd"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, innerDiameter / 2, 0, 2 * Math.PI); context.fill(); if (innerDiameter > 20) { context.fillStyle = "#fff"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, innerDiameter / 2 - 10, 0, 2 * Math.PI); context.fill(); context.fillStyle = "#ddd"; context.fillRect(leftSpace + diameter / 2 - 4, topSpace + 10 + wallThickness, 8, innerDiameter - 20); context.fillRect(leftSpace + 10 + wallThickness, topSpace + diameter / 2 - 4, innerDiameter - 20, 8); context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, 10, 0, 2 * Math.PI); context.fill(); context.fillStyle = "#fff"; context.beginPath(); context.arc(leftSpace + diameter / 2, topSpace + diameter / 2, 3, 0, 2 * Math.PI); context.fill(); } // Draw left vertical line and horizontal lines drawLeftVerticalLine(context, leftSpace, topSpace, diameter, width, innerDiameter); } function drawLeftVerticalLine(context, leftSpace, topSpace, diameter, width, innerDiameter) { context.strokeStyle = "#000"; context.setLineDash([5, 5]); // Calculate sidewall height let sidewallHeight = (diameter - innerDiameter) / 2; let wheelLineY = topSpace + diameter - sidewallHeight; // Draw the left vertical dashed line from the top to the adjusted bottom horizontal line context.beginPath(); context.moveTo(leftSpace - 20, topSpace); context.lineTo(leftSpace - 20, wheelLineY); context.stroke(); context.setLineDash([]); // Draw the top horizontal line context.beginPath(); context.moveTo(leftSpace - 35, topSpace); context.lineTo(leftSpace - 5, topSpace); context.stroke(); // Draw the sidewall height line context.beginPath(); context.moveTo(leftSpace - 35, topSpace + sidewallHeight); context.lineTo(leftSpace - 5, topSpace + sidewallHeight); context.stroke(); // Add text for sidewall height let sidewallText = sidewallHeight.toFixed(2) + (currentUnit === 'mm' ? 'mm' : 'in'); let sidewallTextX = leftSpace - 40; let sidewallTextY = topSpace + sidewallHeight / 2 + 5; context.font = "12px Arial"; context.fillStyle = "#ff0000"; context.textAlign = "right"; context.fillText(sidewallText, sidewallTextX, sidewallTextY); // Draw the bottom horizontal line for wheel size context.beginPath(); context.moveTo(leftSpace - 35, wheelLineY); context.lineTo(leftSpace - 5, wheelLineY); context.stroke(); // Add text for wheel size let wheelText = width.toFixed(2) + (currentUnit === 'mm' ? 'mm' : 'in'); let wheelTextX = leftSpace - 40; let wheelTextY = wheelLineY - 5; context.fillText(wheelText, wheelTextX, wheelTextY); } function drawSideTire(context, leftSpace, topSpace, width, diameter) { context.fillStyle = "#666"; context.beginPath(); context.moveTo(leftSpace, topSpace + diameter * 0.1); context.lineTo(leftSpace + width * 0.1, topSpace); context.lineTo(leftSpace + width * 0.9, topSpace); context.lineTo(leftSpace + width, topSpace + diameter * 0.1); context.lineTo(leftSpace + width, topSpace + diameter * 0.9); context.lineTo(leftSpace + width * 0.9, topSpace + diameter); context.lineTo(leftSpace + width * 0.1, topSpace + diameter); context.lineTo(leftSpace, topSpace + diameter * 0.9); context.closePath(); context.fill(); context.fillStyle = "#000"; context.fillRect(leftSpace + width * 0.1, topSpace, width * 0.8, diameter); context.fillStyle = "#333"; context.fillRect(leftSpace + width * 0.3, topSpace, width * 0.1, diameter); context.fillRect(leftSpace + width * 0.6, topSpace, width * 0.1, diameter); // Draw the dotted line context.setLineDash([5, 3]); context.beginPath(); context.moveTo(leftSpace, topSpace + diameter + 20); context.lineTo(leftSpace + width, topSpace + diameter + 20); context.strokeStyle = '#000'; context.stroke(); context.setLineDash([]); const verticalLength = 20; context.beginPath(); const topPoint = topSpace + diameter + 10; const bottomPoint = topPoint + verticalLength; // Draw the vertical lines context.moveTo(leftSpace, topPoint); context.lineTo(leftSpace, bottomPoint); context.moveTo(leftSpace + width, topPoint); context.lineTo(leftSpace + width, bottomPoint); context.strokeStyle = '#000'; context.stroke(); // Draw the width text below the dotted line context.font = '12px Arial'; context.fillStyle = '#ff0000'; context.textAlign = 'center'; context.fillText(`${width.toFixed(2)} ${currentUnit === 'mm' ? 'mm' : 'in'}`, leftSpace + width / 2, topSpace + diameter + 40); } function drawVerticalLine(context, leftSpace, topSpace, frontDiameter, sideDiameter, overallDiameter) { let frontBottom = topSpace + frontDiameter; let sideBottom = topSpace + sideDiameter; let middleY = (frontBottom + sideBottom) / 2; context.strokeStyle = "#000"; context.setLineDash([5, 5]); context.beginPath(); context.moveTo(leftSpace + frontDiameter / 2 + 230, middleY); context.lineTo(leftSpace + frontDiameter / 2 + 230, topSpace); context.stroke(); context.setLineDash([]); // Add text in the middle let text = overallDiameter.toFixed(2) + (currentUnit === 'mm' ? 'mm' : 'in'); let textX = leftSpace + frontDiameter / 2 + 260; let textY = (middleY + topSpace) / 2; context.font = "12px Arial"; context.fillStyle = "#ff0000"; context.textAlign = "center"; context.fillText(text, textX, textY); // Draw horizontal lines at top and bottom of the left vertical line let horizontalLineLength = 160; context.setLineDash([]); // Draw the top horizontal line context.beginPath(); context.moveTo(leftSpace + frontDiameter / 2 + 220, topSpace); context.lineTo(leftSpace + frontDiameter / 2 + 240, topSpace); context.stroke(); // Draw the bottom horizontal line context.beginPath(); context.moveTo(leftSpace + frontDiameter / 2 + 220, middleY); context.lineTo(leftSpace + frontDiameter / 2 + 240, middleY); context.stroke(); }