| @@ -0,0 +1,293 @@ | |||
| LoRa Irrigation System | |||
| ====================== | |||
| This project is to build an irrigation system from LoRa capable | |||
| microcontrollers. The [Heltec Node151](https://heltec.org/project/lora-node-151/) | |||
| was chosen due to it's small size and inexpensive cost. | |||
| Design Decisions | |||
| ---------------- | |||
| While investigating this project, the LoraWAN protocol was investigated, | |||
| but after looking at the code complexity and other operational | |||
| requirements, if was decided that for this project, it was safer to | |||
| target a direct Node to Node style communication system. This would | |||
| allow the implementation to be more simple, and security to be built in | |||
| (LoRaWAN does have a crypto layer, BUT, trusting/auditing it and any | |||
| library that implements it would be a larger task than I want to | |||
| undertake). It could also be used for other projects that need | |||
| security. | |||
| One of the other requirements is that the code be 100% open sourced, | |||
| not GPL licensed, and no proprietary components. This meant that using | |||
| IDE's like ST's STM32CubeIDE which is only available in binary form | |||
| was not a choice, as that would preclude building on an operating | |||
| system other than Windows/MacOSX/Linux. | |||
| Architecture | |||
| ------------ | |||
| There are a number of components to make this system work. The overall | |||
| flow is: | |||
| <!-- If using MarkDeep, remove the triple backticks from this and the diagram below --> | |||
| ``` | |||
| ************************************************************************************************ | |||
| * * | |||
| * +---------+ +-------------+ +-------------+ +--------------+ * | |||
| * | lora.py | multicast | loraserv.py | USB VCP | lora.gw.elf | LoRa | lora.irr.elf | * | |||
| * | +--------------+ +------------+ main.c +---------+ irr_main.c | * | |||
| * +---------+ +-------------+ +-------------+ +--------------+ * | |||
| * * | |||
| ************************************************************************************************ | |||
| ``` | |||
| The `lora.py` component is the front end/UI that is used to send commands | |||
| to controller. This program establishes a secure communications channel | |||
| to the controller. The controller's firmware is in `lora.irr.elf`, and | |||
| the main source file is `irr_main.c`. | |||
| The middle to components, `loraserv.py` and `lora.gw.elf` are used to | |||
| pass messages between the former two. The `loraserv.py` program takes | |||
| multicast datagrams that are received on 239.192.76.111:21089, which | |||
| are with out any framing, prepends `pkt:`, hex encodes the data and | |||
| terminated w/ the new line character, and sends them via the USB VCP | |||
| provided by `lora.gw.elf`. The gateway firmware then decodes the | |||
| packet and transmits it via the LoRa radio to the irrigation | |||
| controller. Any received packet is returned similarly, but this time | |||
| with `data:` prepended, for `loraserv.py` to multicast back to | |||
| `lora.py`. | |||
| The reason no particular framing is required for addressing or | |||
| destination is that the protocol is secure, and only the party that | |||
| is able to decrypt the proper packets will be accepted, and any invalid | |||
| packets will be ignored. | |||
| Building | |||
| -------- | |||
| The build system uses the BSD flavor of make. This is the default | |||
| make on the BSDs, originally called pmake, but also available as bsdmake | |||
| for MacOSX, and available as [bmake](https://crufty.net/help/sjg/bmake.html). | |||
| It also depends upon ARM's [GNU Arm Embedded | |||
| Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm), | |||
| which uses gcc as the compiler. It would be good to get it | |||
| cross-compile with clang as well, but that requires finding a libc like | |||
| the nano libc that is provided by the toolchain. | |||
| One of the required parameters of the build is the shared key used for | |||
| authentication. A random key can be made using the command: | |||
| `make irrigation_key`, or it can be provided via the make command by | |||
| setting the variable IRR_KEY. | |||
| Note: Both IRR_KEY and the argument to `lora.py` will encode the | |||
| provided key to UTF-8. | |||
| Once ARM's toolchain is in your path, the following should work: | |||
| ``` | |||
| export MAKEOBJDIR=build | |||
| mkdir $MAKEOBJDIR | |||
| bsdmake all IRR_KEY=<sharedkey> | |||
| ``` | |||
| And in the directory `build`, two files, `lora.irr.elf` and | |||
| `lora.gw.elf` should be present. The file `lora.irr.elf` should be | |||
| flashed on the Node151 device that is used for interfacing to the | |||
| irrigation system as described in [Deploying](#deploying). The file | |||
| `lora.gw.elf` should be used on another Node151 that will be attached | |||
| to a computer used as the gateway which runs the `loraserv.py` software | |||
| as described in [Using](#using). | |||
| Flashing | |||
| -------- | |||
| Flashing can be done via the open source tool | |||
| [OpenOCD](https://sourceforge.net/projects/openocd/). For this, I use | |||
| a Digilent HS1 JTAG programmer utilizing the [resistor | |||
| hack](https://github.com/ntfreak/openocd/blob/master/tcl/interface/ftdi/swd-resistor-hack.cfg) | |||
| to allow an FTDI JTAG programmer to control the bi-directional `SWIO` | |||
| pin. | |||
| One caveat w/ MacOSX, is that it may be necessary to unload the kext | |||
| `com.apple.driver.AppleUSBFTDI` via the command: | |||
| ``` | |||
| sudo kextunload -b com.apple.driver.AppleUSBFTDI | |||
| ``` | |||
| as OpenOCD wants direct access to the FTDI driver. | |||
| Once that happens, the device can be programmed using the following | |||
| command: | |||
| ``` | |||
| sudo openocd -f interface/ftdi/digilent-hs1.cfg -f interface/ftdi/swd-resistor-hack.cfg -f target/stm32l1.cfg -c "init" -c "reset init" -c "program build/lora.irr.elf verify reset exit" | |||
| ``` | |||
| Pins | |||
| ---- | |||
| The [pinout guide for the Node151](https://resource.heltec.cn/download/LoRa_Node_151/LoRa_Node_151_Pinout_Diagram.pdf). | |||
| The default pins PB5-7,9 are used as active low controls for the relays. | |||
| They are mapped to channels 0 through 3 respectively. The LED on PB8 | |||
| is mapped to channel 4. This is useful for testing if a command works | |||
| or not. | |||
| The pin PB15 is used as an analog input for an RNG source. This pin | |||
| should be grounded. | |||
| Deploying | |||
| --------- | |||
| Here is a diagram of the connections: | |||
| ``` | |||
| ******************************************************************************************* | |||
| * * | |||
| * GND * | |||
| * +--------------------------------------------------+ * | |||
| * | | * | |||
| * +--------+ ~/~ +-+-----------+ GND +---------+ GPIO +-+--------------+ * | |||
| * | 24V AC +--------+ +----------------+ Node151 +---------+ Relay | * | |||
| * +--------+ | | +-+-------+ +-+--------------+ * | |||
| * | | +5V -> VUSB | | * | |||
| * | AC-DC PS 5V +------------------+ | +5V -> JD-VCC * | |||
| * | | | * | |||
| * | | | * | |||
| * | +--------------------------------------+ * | |||
| * +-------------+ * | |||
| * * | |||
| ******************************************************************************************* | |||
| ``` | |||
| The normal supply used for irrigation values is 24V AC. This means | |||
| an additional power supply is needed to convert to the 5V supply that | |||
| is used by the Node151. Make sure this is well filtered as both the | |||
| relays on the board (talked about below), and the irrigation valves | |||
| will cause significant noise. The first PS I made was a simple DC-DC | |||
| buck converter + a full wave rectifier which, while alone was enough | |||
| to power the uC, was not enough when the relays were actuated, and even | |||
| when a little bit of filtering was added after the rectifier (22uF), | |||
| enough to keep it happy w/ the relays, it was not enough when the | |||
| irrigation valves actuated. | |||
| In order to control the values, a relay board, similar to [this | |||
| one](https://www.amazon.com/ELEGOO-Channel-Optocoupler-Arduino-Raspberry/dp/B01HEQF5HU), | |||
| can be used. Despite the GPIO on the Node151 being 3.3V, and the | |||
| relays requiring 5V, the jumper on the right side, VCC-JD-VCC, can be | |||
| removed to allow dual voltage operation. The GND on the input/VCC | |||
| pinout actually belongs to the relay power via JD-VCC, and NOT for the | |||
| VCC->INx pins, despite them being next to each other. The GND and | |||
| JD-VCC should be connected to the 5V power supply, while VCC is | |||
| connected to VDD on the Node151, and INx pins to the respective | |||
| GPIO pins. | |||
| Using | |||
| ----- | |||
| The `lora.py` script requires at least Python 3.8. It also uses the | |||
| strobe library that in distributed in this repo. In general a | |||
| [virtualenv](https://virtualenv.pypa.io/en/latest/) is recommended for | |||
| all installed Python software to prevent version conflicts, but is not | |||
| always necessary. The `requirements.txt` file contains the necessary | |||
| modules to be installed, but simply adding the directory | |||
| `strobe/python` to PYTHONPATH should be sufficient. | |||
| The program `loraserv.py` takes a single argument, which is the device | |||
| file for the VCP that runs on the gateway. In my case, the device | |||
| name is `/dev/cu.usbmodem1451` as I am on my MacBook Pro, so the command | |||
| to launch the gateway is simply: | |||
| ``` | |||
| python3 loraserv.py /dev/cu.usbmodem1451 | |||
| ``` | |||
| Note: On FreeBSD, the default open mode echos characters back to the | |||
| gateway causing it not to work. It is advised to setup the modem tty | |||
| via the command: | |||
| ``` | |||
| stty -f /dev/cuaU0.init gfmt1:cflag=cb00:iflag=2e02:lflag=43:oflag=2:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:erase2=8:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=9600:ospeed=9600 | |||
| ``` | |||
| before running the `loraserv.py` command. Replace `/dev/cuaU0.init` | |||
| with the respective device. The above was generated by running | |||
| `cu -l /dev/cuaU0` in one terminal, while obtaining the info via | |||
| `stty -g -f /dev/cuaU0` in another terminal. | |||
| Once that is running, then the `lora.py` program's multicast packets | |||
| will be forwarded out via the LoRa radio. | |||
| To test it, a simple `ping` command can be used, or turning on or off | |||
| the on board LED via channel 4 using the `setunset` command. The ping | |||
| command: | |||
| ``` | |||
| python3 lora.py -s <sharedkey> ping | |||
| ``` | |||
| To turn off the LED (which defaults to on): | |||
| ``` | |||
| python3 lora.py -s <sharedkey> setunset 4 0 | |||
| ``` | |||
| Either of these commands should exit w/o message or error. | |||
| Multiple commands may be specified by separating them w/ `--` (two | |||
| hyphens). For example: | |||
| ``` | |||
| python3 lora.py -s <sharedkey> -- setunset 4 0 -- setunset 1 1 | |||
| ``` | |||
| The first `--` is required to denote the end of option parsing, | |||
| otherwise the second `--` will be used, and the first `setunset` | |||
| command will be tried to be parsed as an argument. | |||
| If you have regular set of commands to run, they can be stored in a | |||
| file. Each line will be a single command, so you can have a file | |||
| similar to: | |||
| ``` | |||
| waitfor 5000 | |||
| setunset 0 0 | |||
| setunset 1 0 | |||
| setunset 2 0 | |||
| setunset 3 0 | |||
| runfor 60000 0 | |||
| waitfor 2000 | |||
| runfor 60000 1 | |||
| waitfor 2000 | |||
| runfor 60000 2 | |||
| waitfor 2000 | |||
| runfor 60000 3 | |||
| ``` | |||
| which will make sure all the valves are turned off, then run each one | |||
| in succession for 60 seconds, with a 2 second wait between. | |||
| There are two types of commands, ones that execute immediately, and ones | |||
| that are queued up for future execution. The immediate commands are: | |||
| * `adv`: Sets the current executing command to 0. An optional argument | |||
| specifies how many commands to advance by. Note that only the time | |||
| they are run is set to zero, so channels will be very briefly | |||
| activated. See the clear command to avoid this. | |||
| * `clear`: No argument, removes any future commands. Current command | |||
| remains executing. To clear all commands and stop all operations, | |||
| first do a `clear`, followed by an `adv`. | |||
| * `ping`: No argument, used to verify communication works. | |||
| * `setunset`: First argument is channel, second argument is 0 or 1, | |||
| specifying to turn the channel off (0) or on (1). | |||
| The following commands are queued. The first argument is the number | |||
| of milliseconds to run the command for before advancing to the next | |||
| command. The available commands are: | |||
| * `runfor`: And additional argument specifies the channel. The | |||
| channel will be set to on, and then when the command completes, The | |||
| channel will be set to off. | |||
| * `waitfor`: Wait for the specified time before advancing to the next | |||
| enqueued command. | |||
| Notes | |||
| ----- | |||
| Significant portions of this code is copied from various reference | |||
| implementations. Basic review shows that it is of questionable quality. | |||
| It would be good to fully review all the code under stm32 and loramac | |||
| for any bugs and other issues. The buffer handling has already been | |||
| improved, but there is still plety of work that can be done to improve | |||
| it further. | |||
| <!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js" charset="utf-8"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js" charset="utf-8"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script> | |||
| @@ -1,293 +1,19 @@ | |||
| LoRa Irrigation System | |||
| ====================== | |||
| Syote: Secure IoT | |||
| ================= | |||
| This project is to build an irrigation system from LoRa capable | |||
| microcontrollers. The [Heltec Node151](https://heltec.org/project/lora-node-151/) | |||
| was chosen due to it's small size and inexpensive cost. | |||
| This project started off as a project to control an [irrigation system | |||
| via a LoRa radio](LORA-IRR.md), but the core architecture of the | |||
| communication and security can easily be reused for other projects. | |||
| Design Decisions | |||
| ---------------- | |||
| The projects that make use of the core protocol are included in this | |||
| repo to make development easier for now, but if/when the project gets | |||
| large enough, they will be broken out into their own repositories. | |||
| While investigating this project, the LoraWAN protocol was investigated, | |||
| but after looking at the code complexity and other operational | |||
| requirements, if was decided that for this project, it was safer to | |||
| target a direct Node to Node style communication system. This would | |||
| allow the implementation to be more simple, and security to be built in | |||
| (LoRaWAN does have a crypto layer, BUT, trusting/auditing it and any | |||
| library that implements it would be a larger task than I want to | |||
| undertake). It could also be used for other projects that need | |||
| security. | |||
| One of the other requirements is that the code be 100% open sourced, | |||
| not GPL licensed, and no proprietary components. This meant that using | |||
| IDE's like ST's STM32CubeIDE which is only available in binary form | |||
| was not a choice, as that would preclude building on an operating | |||
| system other than Windows/MacOSX/Linux. | |||
| Architecture | |||
| ------------ | |||
| There are a number of components to make this system work. The overall | |||
| flow is: | |||
| <!-- If using MarkDeep, remove the triple backticks from this and the diagram below --> | |||
| ``` | |||
| ************************************************************************************************ | |||
| * * | |||
| * +---------+ +-------------+ +-------------+ +--------------+ * | |||
| * | lora.py | multicast | loraserv.py | USB VCP | lora.gw.elf | LoRa | lora.irr.elf | * | |||
| * | +--------------+ +------------+ main.c +---------+ irr_main.c | * | |||
| * +---------+ +-------------+ +-------------+ +--------------+ * | |||
| * * | |||
| ************************************************************************************************ | |||
| ``` | |||
| The `lora.py` component is the front end/UI that is used to send commands | |||
| to controller. This program establishes a secure communications channel | |||
| to the controller. The controller's firmware is in `lora.irr.elf`, and | |||
| the main source file is `irr_main.c`. | |||
| The middle to components, `loraserv.py` and `lora.gw.elf` are used to | |||
| pass messages between the former two. The `loraserv.py` program takes | |||
| multicast datagrams that are received on 239.192.76.111:21089, which | |||
| are with out any framing, prepends `pkt:`, hex encodes the data and | |||
| terminated w/ the new line character, and sends them via the USB VCP | |||
| provided by `lora.gw.elf`. The gateway firmware then decodes the | |||
| packet and transmits it via the LoRa radio to the irrigation | |||
| controller. Any received packet is returned similarly, but this time | |||
| with `data:` prepended, for `loraserv.py` to multicast back to | |||
| `lora.py`. | |||
| The reason no particular framing is required for addressing or | |||
| destination is that the protocol is secure, and only the party that | |||
| is able to decrypt the proper packets will be accepted, and any invalid | |||
| packets will be ignored. | |||
| Building | |||
| Projects | |||
| -------- | |||
| The build system uses the BSD flavor of make. This is the default | |||
| make on the BSDs, originally called pmake, but also available as bsdmake | |||
| for MacOSX, and available as [bmake](https://crufty.net/help/sjg/bmake.html). | |||
| It also depends upon ARM's [GNU Arm Embedded | |||
| Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm), | |||
| which uses gcc as the compiler. It would be good to get it | |||
| cross-compile with clang as well, but that requires finding a libc like | |||
| the nano libc that is provided by the toolchain. | |||
| One of the required parameters of the build is the shared key used for | |||
| authentication. A random key can be made using the command: | |||
| `make irrigation_key`, or it can be provided via the make command by | |||
| setting the variable IRR_KEY. | |||
| Note: Both IRR_KEY and the argument to `lora.py` will encode the | |||
| provided key to UTF-8. | |||
| Once ARM's toolchain is in your path, the following should work: | |||
| ``` | |||
| export MAKEOBJDIR=build | |||
| mkdir $MAKEOBJDIR | |||
| bsdmake all IRR_KEY=<sharedkey> | |||
| ``` | |||
| And in the directory `build`, two files, `lora.irr.elf` and | |||
| `lora.gw.elf` should be present. The file `lora.irr.elf` should be | |||
| flashed on the Node151 device that is used for interfacing to the | |||
| irrigation system as described in [Deploying](#deploying). The file | |||
| `lora.gw.elf` should be used on another Node151 that will be attached | |||
| to a computer used as the gateway which runs the `loraserv.py` software | |||
| as described in [Using](#using). | |||
| Flashing | |||
| -------- | |||
| Flashing can be done via the open source tool | |||
| [OpenOCD](https://sourceforge.net/projects/openocd/). For this, I use | |||
| a Digilent HS1 JTAG programmer utilizing the [resistor | |||
| hack](https://github.com/ntfreak/openocd/blob/master/tcl/interface/ftdi/swd-resistor-hack.cfg) | |||
| to allow an FTDI JTAG programmer to control the bi-directional `SWIO` | |||
| pin. | |||
| One caveat w/ MacOSX, is that it may be necessary to unload the kext | |||
| `com.apple.driver.AppleUSBFTDI` via the command: | |||
| ``` | |||
| sudo kextunload -b com.apple.driver.AppleUSBFTDI | |||
| ``` | |||
| as OpenOCD wants direct access to the FTDI driver. | |||
| Once that happens, the device can be programmed using the following | |||
| command: | |||
| ``` | |||
| sudo openocd -f interface/ftdi/digilent-hs1.cfg -f interface/ftdi/swd-resistor-hack.cfg -f target/stm32l1.cfg -c "init" -c "reset init" -c "program build/lora.irr.elf verify reset exit" | |||
| ``` | |||
| Pins | |||
| ---- | |||
| The [pinout guide for the Node151](https://resource.heltec.cn/download/LoRa_Node_151/LoRa_Node_151_Pinout_Diagram.pdf). | |||
| The default pins PB5-7,9 are used as active low controls for the relays. | |||
| They are mapped to channels 0 through 3 respectively. The LED on PB8 | |||
| is mapped to channel 4. This is useful for testing if a command works | |||
| or not. | |||
| The pin PB15 is used as an analog input for an RNG source. This pin | |||
| should be grounded. | |||
| Deploying | |||
| --------- | |||
| Here is a diagram of the connections: | |||
| ``` | |||
| ******************************************************************************************* | |||
| * * | |||
| * GND * | |||
| * +--------------------------------------------------+ * | |||
| * | | * | |||
| * +--------+ ~/~ +-+-----------+ GND +---------+ GPIO +-+--------------+ * | |||
| * | 24V AC +--------+ +----------------+ Node151 +---------+ Relay | * | |||
| * +--------+ | | +-+-------+ +-+--------------+ * | |||
| * | | +5V -> VUSB | | * | |||
| * | AC-DC PS 5V +------------------+ | +5V -> JD-VCC * | |||
| * | | | * | |||
| * | | | * | |||
| * | +--------------------------------------+ * | |||
| * +-------------+ * | |||
| * * | |||
| ******************************************************************************************* | |||
| ``` | |||
| The normal supply used for irrigation values is 24V AC. This means | |||
| an additional power supply is needed to convert to the 5V supply that | |||
| is used by the Node151. Make sure this is well filtered as both the | |||
| relays on the board (talked about below), and the irrigation valves | |||
| will cause significant noise. The first PS I made was a simple DC-DC | |||
| buck converter + a full wave rectifier which, while alone was enough | |||
| to power the uC, was not enough when the relays were actuated, and even | |||
| when a little bit of filtering was added after the rectifier (22uF), | |||
| enough to keep it happy w/ the relays, it was not enough when the | |||
| irrigation valves actuated. | |||
| In order to control the values, a relay board, similar to [this | |||
| one](https://www.amazon.com/ELEGOO-Channel-Optocoupler-Arduino-Raspberry/dp/B01HEQF5HU), | |||
| can be used. Despite the GPIO on the Node151 being 3.3V, and the | |||
| relays requiring 5V, the jumper on the right side, VCC-JD-VCC, can be | |||
| removed to allow dual voltage operation. The GND on the input/VCC | |||
| pinout actually belongs to the relay power via JD-VCC, and NOT for the | |||
| VCC->INx pins, despite them being next to each other. The GND and | |||
| JD-VCC should be connected to the 5V power supply, while VCC is | |||
| connected to VDD on the Node151, and INx pins to the respective | |||
| GPIO pins. | |||
| Using | |||
| ----- | |||
| The `lora.py` script requires at least Python 3.8. It also uses the | |||
| strobe library that in distributed in this repo. In general a | |||
| [virtualenv](https://virtualenv.pypa.io/en/latest/) is recommended for | |||
| all installed Python software to prevent version conflicts, but is not | |||
| always necessary. The `requirements.txt` file contains the necessary | |||
| modules to be installed, but simply adding the directory | |||
| `strobe/python` to PYTHONPATH should be sufficient. | |||
| The program `loraserv.py` takes a single argument, which is the device | |||
| file for the VCP that runs on the gateway. In my case, the device | |||
| name is `/dev/cu.usbmodem1451` as I am on my MacBook Pro, so the command | |||
| to launch the gateway is simply: | |||
| ``` | |||
| python3 loraserv.py /dev/cu.usbmodem1451 | |||
| ``` | |||
| Note: On FreeBSD, the default open mode echos characters back to the | |||
| gateway causing it not to work. It is advised to setup the modem tty | |||
| via the command: | |||
| ``` | |||
| stty -f /dev/cuaU0.init gfmt1:cflag=cb00:iflag=2e02:lflag=43:oflag=2:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:erase2=8:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=9600:ospeed=9600 | |||
| ``` | |||
| before running the `loraserv.py` command. Replace `/dev/cuaU0.init` | |||
| with the respective device. The above was generated by running | |||
| `cu -l /dev/cuaU0` in one terminal, while obtaining the info via | |||
| `stty -g -f /dev/cuaU0` in another terminal. | |||
| Once that is running, then the `lora.py` program's multicast packets | |||
| will be forwarded out via the LoRa radio. | |||
| To test it, a simple `ping` command can be used, or turning on or off | |||
| the on board LED via channel 4 using the `setunset` command. The ping | |||
| command: | |||
| ``` | |||
| python3 lora.py -s <sharedkey> ping | |||
| ``` | |||
| To turn off the LED (which defaults to on): | |||
| ``` | |||
| python3 lora.py -s <sharedkey> setunset 4 0 | |||
| ``` | |||
| Either of these commands should exit w/o message or error. | |||
| Multiple commands may be specified by separating them w/ `--` (two | |||
| hyphens). For example: | |||
| ``` | |||
| python3 lora.py -s <sharedkey> -- setunset 4 0 -- setunset 1 1 | |||
| ``` | |||
| The first `--` is required to denote the end of option parsing, | |||
| otherwise the second `--` will be used, and the first `setunset` | |||
| command will be tried to be parsed as an argument. | |||
| If you have regular set of commands to run, they can be stored in a | |||
| file. Each line will be a single command, so you can have a file | |||
| similar to: | |||
| ``` | |||
| waitfor 5000 | |||
| setunset 0 0 | |||
| setunset 1 0 | |||
| setunset 2 0 | |||
| setunset 3 0 | |||
| runfor 60000 0 | |||
| waitfor 2000 | |||
| runfor 60000 1 | |||
| waitfor 2000 | |||
| runfor 60000 2 | |||
| waitfor 2000 | |||
| runfor 60000 3 | |||
| ``` | |||
| which will make sure all the valves are turned off, then run each one | |||
| in succession for 60 seconds, with a 2 second wait between. | |||
| There are two types of commands, ones that execute immediately, and ones | |||
| that are queued up for future execution. The immediate commands are: | |||
| * `adv`: Sets the current executing command to 0. An optional argument | |||
| specifies how many commands to advance by. Note that only the time | |||
| they are run is set to zero, so channels will be very briefly | |||
| activated. See the clear command to avoid this. | |||
| * `clear`: No argument, removes any future commands. Current command | |||
| remains executing. To clear all commands and stop all operations, | |||
| first do a `clear`, followed by an `adv`. | |||
| * `ping`: No argument, used to verify communication works. | |||
| * `setunset`: First argument is channel, second argument is 0 or 1, | |||
| specifying to turn the channel off (0) or on (1). | |||
| The following commands are queued. The first argument is the number | |||
| of milliseconds to run the command for before advancing to the next | |||
| command. The available commands are: | |||
| * `runfor`: And additional argument specifies the channel. The | |||
| channel will be set to on, and then when the command completes, The | |||
| channel will be set to off. | |||
| * `waitfor`: Wait for the specified time before advancing to the next | |||
| enqueued command. | |||
| Notes | |||
| ----- | |||
| [LoRa Irrigation](LORA-IRR.md): Control over LoRa radio. | |||
| Significant portions of this code is copied from various reference | |||
| implementations. Basic review shows that it is of questionable quality. | |||
| It would be good to fully review all the code under stm32 and loramac | |||
| for any bugs and other issues. The buffer handling has already been | |||
| improved, but there is still plety of work that can be done to improve | |||
| it further. | |||
| [RS-485 USB HID KVM](RS485HID.md): USB Keyboard over RS-485 | |||
| <!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js" charset="utf-8"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js" charset="utf-8"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script> | |||
| @@ -0,0 +1,54 @@ | |||
| USB Keyboard over RS-485 | |||
| ======================== | |||
| The project is to have a device that appears to a computer as a USB | |||
| keyboard, but it receives it's key presses from another computer via an | |||
| RS-485 multidrop bus. It will use the Syote library for communications, | |||
| and as there can be multiple devices on the bus, a single gateway | |||
| controller can service multiple such keyboards, making it a nice option | |||
| for an IPMI like solution. It is also expected that GPIOs of the device | |||
| can be used to control the power switches, along with observing various | |||
| LEDs. As most microcontrollers have an ADC, it could theoretically | |||
| support beeps from the PC speaker. | |||
| Devices | |||
| ------- | |||
| These are the device that are under conideration for the project: | |||
| ### STM32F103C8 | |||
| 64KB flash | |||
| Currently looking at USART3, B0 for DE, B1 for RE. | |||
| Table 5 pin definitions of stm32f103c8.pdf | |||
| (all can be remapped) | |||
| USART has idle line detction | |||
| USART1_TX PA9 5v tollerant | |||
| USART1_RX PA10 5v tollerant | |||
| USART2_TX PA2 NOT 5v tollerant | |||
| USART2_RX PA3 NOT 5v tollerant | |||
| USART3_TX PB10 5v tollerant | |||
| USART3_RX PB11 5v tollerant | |||
| flash: 0/x | |||
| boot loader (an2606) pattern 1: 1/0 | |||
| embedded sram: 1/1 | |||
| top jumper BOOT0/44 | |||
| bottom jumper BOOT1/PB2/20 | |||
| ### MAX485 | |||
| This requires a 5V VCC. There is a 3.3V part called the MAX3485, but | |||
| as often micros can be 5V tollerant, and the MAX485 is fine w/ logic | |||
| levels down to 2V, this should be fine. | |||
| D - Driver | |||
| DE Driver enable (high enable) | |||
| DI Driver input | |||
| R - Receiver | |||
| RO Receiver output | |||
| /RE Receiver enable (low enable) | |||