From 75839c9f7eb3b3b35e03abdcc06998d713f31b80 Mon Sep 17 00:00:00 2001 From: Stephen Hawes Date: Mon, 29 Jan 2024 18:42:23 -0500 Subject: [PATCH] moves firmware flashing instructions to the guides section, and adds some photon docs hidden in an island as they're not complete --- docs/byop/motherboard/mounting/index.md | 2 +- .../update-firmware/images/IMG_0749.JPG | Bin .../images/PIO_upload_done.png | Bin .../images/STM32_COM_port_connected.png | Bin .../Screen Shot 2022-02-04 at 7.27.25 PM.png | Bin .../images/browse-for-binary.png | Bin .../images/connect-to-motherboard.png | Bin .../images/connect_STM_to_programmer.png | Bin .../images/dfu_mode_device_manager.png | Bin .../update-firmware/images/download-tab.png | Bin .../images/firmware_download_done.png | Bin .../update-firmware/images/linux_lsusb.png | Bin .../images/linux_lsusb_bootloader.png | Bin .../images/marlin-auto-build-ui.png | Bin .../images/open_firmware_bin_file.png | Bin .../update-firmware/images/rect34.png | Bin .../update-firmware/images/refresh-button.png | Bin .../update-firmware/images/select-port.png | Bin .../images/start-programming.png | Bin .../images/start_firmware_download.png | Bin .../update-firmware/images/upload-done.png | Bin .../update-firmware/images/usb-connection.png | Bin .../vscode-dfu-util-integrated-terminal.png | Bin .../images/vscode_marlin_env.png | Bin .../update-firmware/index.md | 61 +++--- docs/misc/photon/img/photon-packet.png | Bin 0 -> 48083 bytes docs/misc/photon/index.md | 174 ++++++++++++++++++ mkdocs.yml | 2 + 28 files changed, 207 insertions(+), 32 deletions(-) rename docs/{byop/motherboard => guides}/update-firmware/images/IMG_0749.JPG (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/PIO_upload_done.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/STM32_COM_port_connected.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/Screen Shot 2022-02-04 at 7.27.25 PM.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/browse-for-binary.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/connect-to-motherboard.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/connect_STM_to_programmer.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/dfu_mode_device_manager.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/download-tab.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/firmware_download_done.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/linux_lsusb.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/linux_lsusb_bootloader.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/marlin-auto-build-ui.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/open_firmware_bin_file.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/rect34.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/refresh-button.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/select-port.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/start-programming.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/start_firmware_download.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/upload-done.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/usb-connection.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/vscode-dfu-util-integrated-terminal.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/images/vscode_marlin_env.png (100%) rename docs/{byop/motherboard => guides}/update-firmware/index.md (83%) create mode 100644 docs/misc/photon/img/photon-packet.png create mode 100644 docs/misc/photon/index.md diff --git a/docs/byop/motherboard/mounting/index.md b/docs/byop/motherboard/mounting/index.md index 3abfddfac..916b50c71 100644 --- a/docs/byop/motherboard/mounting/index.md +++ b/docs/byop/motherboard/mounting/index.md @@ -58,4 +58,4 @@ Now that we've got all the THT components soldered in, it's time to mount the mo ## Next steps -Make sure your motherboard is [running the latest firmware](../update-firmware/index.md). +Continue to [wiring and pneumatics](../../wiring-and-pneumatics/wiring-y-motors/index.md). diff --git a/docs/byop/motherboard/update-firmware/images/IMG_0749.JPG b/docs/guides/update-firmware/images/IMG_0749.JPG similarity index 100% rename from docs/byop/motherboard/update-firmware/images/IMG_0749.JPG rename to docs/guides/update-firmware/images/IMG_0749.JPG diff --git a/docs/byop/motherboard/update-firmware/images/PIO_upload_done.png b/docs/guides/update-firmware/images/PIO_upload_done.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/PIO_upload_done.png rename to docs/guides/update-firmware/images/PIO_upload_done.png diff --git a/docs/byop/motherboard/update-firmware/images/STM32_COM_port_connected.png b/docs/guides/update-firmware/images/STM32_COM_port_connected.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/STM32_COM_port_connected.png rename to docs/guides/update-firmware/images/STM32_COM_port_connected.png diff --git a/docs/byop/motherboard/update-firmware/images/Screen Shot 2022-02-04 at 7.27.25 PM.png b/docs/guides/update-firmware/images/Screen Shot 2022-02-04 at 7.27.25 PM.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/Screen Shot 2022-02-04 at 7.27.25 PM.png rename to docs/guides/update-firmware/images/Screen Shot 2022-02-04 at 7.27.25 PM.png diff --git a/docs/byop/motherboard/update-firmware/images/browse-for-binary.png b/docs/guides/update-firmware/images/browse-for-binary.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/browse-for-binary.png rename to docs/guides/update-firmware/images/browse-for-binary.png diff --git a/docs/byop/motherboard/update-firmware/images/connect-to-motherboard.png b/docs/guides/update-firmware/images/connect-to-motherboard.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/connect-to-motherboard.png rename to docs/guides/update-firmware/images/connect-to-motherboard.png diff --git a/docs/byop/motherboard/update-firmware/images/connect_STM_to_programmer.png b/docs/guides/update-firmware/images/connect_STM_to_programmer.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/connect_STM_to_programmer.png rename to docs/guides/update-firmware/images/connect_STM_to_programmer.png diff --git a/docs/byop/motherboard/update-firmware/images/dfu_mode_device_manager.png b/docs/guides/update-firmware/images/dfu_mode_device_manager.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/dfu_mode_device_manager.png rename to docs/guides/update-firmware/images/dfu_mode_device_manager.png diff --git a/docs/byop/motherboard/update-firmware/images/download-tab.png b/docs/guides/update-firmware/images/download-tab.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/download-tab.png rename to docs/guides/update-firmware/images/download-tab.png diff --git a/docs/byop/motherboard/update-firmware/images/firmware_download_done.png b/docs/guides/update-firmware/images/firmware_download_done.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/firmware_download_done.png rename to docs/guides/update-firmware/images/firmware_download_done.png diff --git a/docs/byop/motherboard/update-firmware/images/linux_lsusb.png b/docs/guides/update-firmware/images/linux_lsusb.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/linux_lsusb.png rename to docs/guides/update-firmware/images/linux_lsusb.png diff --git a/docs/byop/motherboard/update-firmware/images/linux_lsusb_bootloader.png b/docs/guides/update-firmware/images/linux_lsusb_bootloader.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/linux_lsusb_bootloader.png rename to docs/guides/update-firmware/images/linux_lsusb_bootloader.png diff --git a/docs/byop/motherboard/update-firmware/images/marlin-auto-build-ui.png b/docs/guides/update-firmware/images/marlin-auto-build-ui.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/marlin-auto-build-ui.png rename to docs/guides/update-firmware/images/marlin-auto-build-ui.png diff --git a/docs/byop/motherboard/update-firmware/images/open_firmware_bin_file.png b/docs/guides/update-firmware/images/open_firmware_bin_file.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/open_firmware_bin_file.png rename to docs/guides/update-firmware/images/open_firmware_bin_file.png diff --git a/docs/byop/motherboard/update-firmware/images/rect34.png b/docs/guides/update-firmware/images/rect34.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/rect34.png rename to docs/guides/update-firmware/images/rect34.png diff --git a/docs/byop/motherboard/update-firmware/images/refresh-button.png b/docs/guides/update-firmware/images/refresh-button.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/refresh-button.png rename to docs/guides/update-firmware/images/refresh-button.png diff --git a/docs/byop/motherboard/update-firmware/images/select-port.png b/docs/guides/update-firmware/images/select-port.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/select-port.png rename to docs/guides/update-firmware/images/select-port.png diff --git a/docs/byop/motherboard/update-firmware/images/start-programming.png b/docs/guides/update-firmware/images/start-programming.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/start-programming.png rename to docs/guides/update-firmware/images/start-programming.png diff --git a/docs/byop/motherboard/update-firmware/images/start_firmware_download.png b/docs/guides/update-firmware/images/start_firmware_download.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/start_firmware_download.png rename to docs/guides/update-firmware/images/start_firmware_download.png diff --git a/docs/byop/motherboard/update-firmware/images/upload-done.png b/docs/guides/update-firmware/images/upload-done.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/upload-done.png rename to docs/guides/update-firmware/images/upload-done.png diff --git a/docs/byop/motherboard/update-firmware/images/usb-connection.png b/docs/guides/update-firmware/images/usb-connection.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/usb-connection.png rename to docs/guides/update-firmware/images/usb-connection.png diff --git a/docs/byop/motherboard/update-firmware/images/vscode-dfu-util-integrated-terminal.png b/docs/guides/update-firmware/images/vscode-dfu-util-integrated-terminal.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/vscode-dfu-util-integrated-terminal.png rename to docs/guides/update-firmware/images/vscode-dfu-util-integrated-terminal.png diff --git a/docs/byop/motherboard/update-firmware/images/vscode_marlin_env.png b/docs/guides/update-firmware/images/vscode_marlin_env.png similarity index 100% rename from docs/byop/motherboard/update-firmware/images/vscode_marlin_env.png rename to docs/guides/update-firmware/images/vscode_marlin_env.png diff --git a/docs/byop/motherboard/update-firmware/index.md b/docs/guides/update-firmware/index.md similarity index 83% rename from docs/byop/motherboard/update-firmware/index.md rename to docs/guides/update-firmware/index.md index 6742b7ce7..4ba903515 100644 --- a/docs/byop/motherboard/update-firmware/index.md +++ b/docs/guides/update-firmware/index.md @@ -1,19 +1,20 @@ -# Update the Firmware +# Update LumenPnP Firmware -All motherboards come pre-flashed with firmware from Opulo and should work out of the box without these steps. If you're setting up a LumenPnP with feeders for the first time, you may need to update your LumenPnP's firmware. - -!!! danger "Important" - It is important that you pick the correct firmware file for your machine. - - - If you have a v2, choose `v2-lumenpnp-firmware-feeder-support.bin`. - - If you have a v3, choose `v3-lumenpnp-firmware-feeder-support.bin`. +All motherboards come pre-flashed with firmware from Opulo and should work out of the box without these steps. If you need to update your LumenPnP's firmware, this guide will help you do so. ## Option 1: Prebuilt Firmware and STMProgrammer (RECOMMENDED) The easiest way to update your LumenPnP's motherboard is to use a precompiled binary of the firmware, and the [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) software by ST. 1. Download the latest [precompiled firmware](https://github.com/opulo-inc/lumenpnp/releases) `.bin` file for your motherboard version. + + !!! danger "Important" + It is important that you pick the correct firmware file for your machine. + + - If you have a v2, choose `v2-lumenpnp-firmware-feeder-support.bin`. + - If you have a v3, choose `v3-lumenpnp-firmware-feeder-support.bin`. + 2. Download and install [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html). 3. Open STM32CubeProgrammer. 4. Select `USB` from the connection type dropdown on the right. @@ -32,33 +33,33 @@ The easiest way to update your LumenPnP's motherboard is to use a precompiled bi !!! info "NOTE" If you have a hard time getting your board to enter DFU mode, instead try powering off the machine entirely, holding the 'BOOT' button, plugging in power, waiting 10 seconds, then release the `BOOT` button. -8. Click the refresh button in the `Port` line to detect the motherboard's port. +1. Click the refresh button in the `Port` line to detect the motherboard's port. ![Refresh button](images/refresh-button.png) -9. Select the newly discovered USB port from the `Port` dropdown menu. +2. Select the newly discovered USB port from the `Port` dropdown menu. ![Select USB Port](images/select-port.png) -10. Double-check the other fields on the right match the image above: +3. Double-check the other fields on the right match the image above: 1. `PID: 0xdf11` 2. `VID: 0x0483` 3. `Read Unprotect (MCU): Unchecked` 4. `TZEN Regression (MCU): Unchecked` -11. Click the green `Connect` button to connect to the motherboard. +4. Click the green `Connect` button to connect to the motherboard. ![Connect to Motherboard button](images/connect-to-motherboard.png) -12. Click the `Browse` button to browse for the binary you downloaded earlier. +5. Click the `Browse` button to browse for the binary you downloaded earlier. ![Click the browse button](images/browse-for-binary.png) -13. Click the `Start Programming` button to upload the firmware to the motherboard. +6. Click the `Start Programming` button to upload the firmware to the motherboard. ![Start Programming the motherboard](images/start-programming.png) -14. Let the upload finish. +7. Let the upload finish. ![Upload finished](images/upload-done.png) -15. Press the `reset` button on the motherboard to reboot it. +8. Press the `reset` button on the motherboard to reboot it. -16. The machine should show up as a COM/Serial Port on your PC now, and you should be able to access it via OpenPNP. If it doesn't, press the Reset button on the board again, or power-cycle the machine *after the flashing is completed*. +9. The machine should show up as a COM/Serial Port on your PC now, and you should be able to access it via OpenPNP. If it doesn't, press the Reset button on the board again, or power-cycle the machine *after the flashing is completed*. This is how you can check whether your machine is connected properly: @@ -67,10 +68,10 @@ This is how you can check whether your machine is connected properly: ## Option 2: Auto Build Marlin and `dfu-util` -!!! info "Marlin" - Building an older version of Marlin with the recommended config files won't work. If you are unsure whether a previously-downloaded local version of Marlin is the newest one, re-downloading it is the safest choice. +!!! info "Marlin Version" + LumenPnP feeders require some custom Marlin features that we have not yet merged into mainline. Before this happens, be sure you're pulling from our fork with these features. -1. Download the [latest Marlin firmware][marlin] and unzip it. +1. Download the [latest Marlin firmware with feeder support][marlin] and unzip it. 2. Install [VSCode][vscode] and its [PlatformIO extension][pIO]. 3. Open Marlin firmware's folder in VSCode. 4. Download the Marlin configuration files [here][marlin-config] and @@ -80,7 +81,7 @@ This is how you can check whether your machine is connected properly: 8. Try to build Marlin using the build button with the hammer icon as shown below. See [Troubleshooting](#troubleshooting-building-with-auto-build-marlin) for more help ![Marlin Auto Build screenshot](images/marlin-auto-build-ui.png) -9. Attach the LumenPnP Motherboard to your computer with the included USB cable (USB C to A for Motherboard 3.0, or USB B to A for Motherboard 4.0). +9. Attach the LumenPnP Motherboard to your computer with the included USB cable (USB C to A for Motherboard 3.0, or USB B to A for Motherboard 4.0). 10. Boot your motherboard into DFU Mode 1. Press and hold the `BOOT` button @@ -92,7 +93,7 @@ This is how you can check whether your machine is connected properly: !!! info "NOTE" If you have a hard time getting your board to enter DFU mode, instead try powering off the machine entirely, holding the 'BOOT' button, plugging in power, waiting 10 seconds, then release the `BOOT` button. -11. In the integrated terminal in the root of the repository, flash the Motherboard using `dfu-util` by running the command: +1. In the integrated terminal in the root of the repository, flash the Motherboard using `dfu-util` by running the command: ```shell dfu-util -d 0x0483:0xdf11 -s 0x08000000:leave -a 0 -D ./.pio/build/Opulo_Lumen_REV3/firmware.bin @@ -107,9 +108,9 @@ This is how you can check whether your machine is connected properly: * `-a 0` makes the tool use the alt setting required for flashing the ESP32. * `-D ./.pio/build/Opulo_Lumen_REV3/firmware.bin` is the path to the to-be-flashed firmware. If you want to flash another file, change this. -12. Wait for the process to finish. +2. Wait for the process to finish. -13. The machine should show up as a COM/Serial Port on your PC now, and you should be able to access it via OpenPNP. If it doesn't, press the Reset button on the board, or power-cycle the machine *after the flashing is completed*. +3. The machine should show up as a COM/Serial Port on your PC now, and you should be able to access it via OpenPNP. If it doesn't, press the Reset button on the board, or power-cycle the machine *after the flashing is completed*. This is how you can check whether your machine is connected properly: @@ -120,7 +121,7 @@ This is how you can check whether your machine is connected properly: Note that flashing the firmware using the Auto Build Marlin Plugin might work, but seems error-prone for most people. We recommend using `dfu-util` as described above. Here are the steps to use Auto Build Marlin if you'd like to try it. -1. Download the [latest Marlin firmware][marlin] and unzip it. +1. Download the [latest Marlin firmware with feeder support][marlin] and unzip it. 2. Install [VSCode][vscode] and its [PlatformIO extension][pIO]. 3. Open Marlin firmware's folder in VSCode. 4. Download the Marlin configuration files [here][marlin-config]. @@ -183,13 +184,13 @@ This is how you can check whether your machine is connected properly: ## Flashing Factory Firmware -If you've put new firmware on your motherboard, but just want to get back to the firmware that your machine was flashed with, check the release for your build number and download the .bin firmware file attached to it. Put your board into DFU mode as described above, connect to your computer, and flash the binary to the board using the following command: +If you've put new firmware on your motherboard, but want to reinstall the firmware that your machine was flashed with, check the release for your build number and download the .bin firmware file attached to it. Put your board into DFU mode as described above, connect to your LumenPnP over USB, and flash the binary to the board using the STMProgrammer tool, or the following command (for Mac and Linux): ```shell -`dfu-util -d 0x0483:0xdf11 -s 0x08000000:leave -a 0 -D ~/path/to/firmware.bin` +dfu-util -d 0x0483:0xdf11 -s 0x08000000:leave -a 0 -D ~/path/to/firmware.bin ``` -Once flashing is completed, the machine should automatically exit DFU mode, and be accessible to OpenPNP again. +Once flashing is completed, press the reset button on the motherboard boot into the new firmware. ## Troubleshooting @@ -210,13 +211,11 @@ If you aren't able to upload, you can check to see if your motherboard is bootin Also, reference [the Marlin instructions for uploading](https://marlinfw.org/docs/basics/install_platformio.html). -## Next steps -Continue to [wiring and pneumatics](../../wiring-and-pneumatics/wiring-y-motors/index.md). [abmvs]: https://marketplace.visualstudio.com/items?itemName=MarlinFirmware.auto-build [marlin-docs]: https://marlinfw.org/docs/basics/auto_build_marlin.html [marlin-config]: https://github.com/MarlinFirmware/Configurations/tree/import-2.1.x/config/examples/Opulo/Lumen_REV4 -[marlin]: https://github.com/MarlinFirmware/Marlin/ +[marlin]: https://github.com/sphawes/Marlin/tree/feeder-safety [vscode]: https://code.visualstudio.com/ [pIO]: https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide diff --git a/docs/misc/photon/img/photon-packet.png b/docs/misc/photon/img/photon-packet.png new file mode 100644 index 0000000000000000000000000000000000000000..b3b1a0ea9b4ac19b346c81865805ea9c6082399a GIT binary patch literal 48083 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 literal 0 HcmV?d00001 diff --git a/docs/misc/photon/index.md b/docs/misc/photon/index.md new file mode 100644 index 000000000..2a107863f --- /dev/null +++ b/docs/misc/photon/index.md @@ -0,0 +1,174 @@ +# Photon Protocol + +The Photon Protocol is designed to facilitate ids and uuids + +Only the host may initiate communication. Every Photon interaction is comprised of two packets: one packet from the host with a command and optional payload, and a response from a feeder with a status and optional payload of information. + +broadcast and unicast + +The following is the basic Photon packet structure. + +![](img/photon-packet.png) + +The packet is made up of two parts: the header and the payload. The header contains exactly five bytes: "to" address, "from" address, packet ID, payload length, and the CRC. The payload *always* has at least one byte, either a command ID or a status. The payload can have optional further bytes. + +## Header Bytes + +### To Address + +This byte indicates which address the packet is intended for. This address value is equivalent to the slot addresses. + +Valid values are anywhere between `0x00` and `0xFF`. Address `0x00` is reserved for the host, and address `0xFF` is reserved for broadcast commands. + +### From Address + +This byte indicates which address the packet is coming from. This address value is equivalent to the slot addresses. + +Valid values are anywhere between `0x00` and `0xFF`. Address `0x00` is reserved for the host. + +### Packet ID + +The Packet ID is an identifying byte that allows the devices on the bus to keep track of requests. When a feeder responds to a command, it includes the Packet ID of the initiating packet. This allows the host to determine which packet the feeder is responding to. + +This byte is a value between `0x00` and `0xFF`. The host should increment this value for every command sent, and roll back to `0x00` once it reaches `0xFF`. + +### Payload Length + +The payload length is the number of bytes contained in the payload. This number will always be at least `0x01`, as each packet has at least a Command ID or Status. + +### CRC + +The CRC byte is a checksum calculated on the entire packet sans the checksum byte. The checksum can be calculated as shown below: + +JavaScript + +``` javascript +calcCRC(data){ + let crc = 0; + for(var i = 0; i> 8) & 0xFF; +} +``` + +C + +``` c +uint8_t crc8(uint8_t data, size_t len) { + uint32_t crc = 0; + + for (size_t i = 0; i < len; i++) { + crc ^= (data << 8); + for (size_t bit_n = 0; bit_n < 8; bit_n++) { + if (crc & 0x8000) { + crc ^= (0x1070 << 3); + } + crc <<= 1; + } + } + + return (uint8_t)(crc >> 8); +} +``` + +Once the CRC is calculated, it should be spliced into the packet in the appropriate location. The CRC should be recalculated and compared with the received CRC for every received packet to confirm data integrity. + +## Payload + +The first byte of the payload is always a Command ID when coming from the host, and always a Status when coming as a response from a feeder. The Command ID tells the feeder what action to perform or what information to send. The Status tells the host the status of the command. + +The rest of the payload is used for any other information that needs to be sent, depending on the situation. + +| Command Code | Name | +| ------ | ----------------------------- | +| `0x01` | Get Feeder ID | +| `0x02` | Initialize Feeder | +| `0x03` | Get Version | +| `0x04` | Move Feed Forward | +| `0x05` | Move Feed Backward | +| `0x06` | Move Feed Status | +| `0xbf` | Vendor Options | +| `0xc0` | Get Feeder Address | +| `0xc1` | Identify Feeder | +| `0xc2` | Program Feeder Floor | +| `0xc3` | Uninitialized Feeders Respond | + +| Status Code | Name | +| ----------- | ---------------------- | +| `0x00` | `OK` | +| `0x01` | `WRONG_FEEDER_ID` | +| `0x02` | `COULDNT_REACH` | +| `0x03` | `UNINITIALIZED_FEEDER` | +| `0x04` | `FEEDING_IN_PROGRESS` | +| `0x05` | `FAIL` | +| `0xFE` | `TIMEOUT` | +| `0xFF` | `UNKNOWN` | + +## Command IDs + +Each Command ID the host can send a feeder have certain payload requirements, and certain expected responses from the feeder. + +### GET_ID `0x01` + +| Send | | +| -------------------- | ------------ | +| Requires Initialized | NO | +| Addressing | UNICAST | +| Payload | NONE | + +| Receive | | | +| -------------------- | ------------ | ------- | +| Status | `OK` | 0 | +| Payload | 12 Byte UUID | 1-13 | + +GET_ID is used to get a feeder's UUID knowing only it's slot address. GET_ID is used mainly to scan the bus address space and see if a feeder is present in a slot, and get its UUID for initilizing. + +#### Example + +Send: +``` +[02] [00] [07] [01] [C0] [01] + | | | | | | + | | | | | Sending Command 0x01 means GET_ID + | | | | | + | | | | Checksum + | | | | + | | | Payload Length of 1 + | | | + | | Packet ID + | | + | From Address + | +To Address +``` + +Receive: +``` +[00] [02] [07] [13] [D7] [00] [02] [48] ..... [37] [30] + | | | | | | |_____________________| + | | | | | | | + | | | | | | | + | | | | | | 12 Byte UUID + | | | | | | + | | | | | Status 0x00 means OK + | | | | | + | | | | Checksum + | | | | + | | | Payload Length of 13 + | | | + | | Packet ID + | | + | From Address + | +To Address +``` + + + diff --git a/mkdocs.yml b/mkdocs.yml index f18a09729..1f1dfba08 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -138,6 +138,7 @@ nav: - Troubleshooting: feeders/8-troubleshooting/troubleshooting.md - Guides: + - Update LumenPnP Firmware: guides/update-firmware/index.md - Change Motor Current: guides/motor-current/index.md - Change Machine Speed: guides/machine-speed/index.md - Change Ring Light Brightness: guides/ring-light-settings/index.md @@ -152,6 +153,7 @@ nav: - Misc: - Backlash Compensation: misc/backlash-compensation/index.md - Automatic Toolchanger: misc/auto-toolchanger/index.md + - Design for LumenPnP: design-for-lumenpnp/index.md