| @@ -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> | <!-- 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) | |||||