diff --git a/.gitignore b/.gitignore index 36f43a44..a5a85fd8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ settings.conf test.sh test.conf *.FCStd1 -/venv/* \ No newline at end of file +/venv*/* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 661364fa..b249bfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,29 @@ # Changelog + +## [2.6.0] - not released +### Added + - Septentrio Mosaic-X5 detection and configuration + - Reverse proxy server with Rtkbase authentication, for Mosaic-X5 web interface + - Added description below form input. #381 + - New optional service, rtkbase_raw2nmea.service, to get date and time with a gnss receiver unknown to gpsd. (CLI only) #394 +### Changed + - RTKLib upgraded to release b34j from rtklibexplorer. + - Switch server from eventlet to gevent + Gunicorn server. +### Deprecated + - Operating systems older than Debian 11 / Ubuntu 22.04 can't update RTKBase anymore. + - Python release < 3.8 deprecated +### Removed + - Eventlet python module is not needed anymore. +### Fixed + - Remove Sbas rtcm message (1107) after F9P configuration. #391 + - Tooltips buttons were a link to top page. #387 + - Fix armbian ramlog bug with log older than 1 day. https://github.com/Stefal/build/issues/16 + - Archive service will compress .sbf files too. + - Fix duplicates in .sbf to rinex conversion : https://github.com/rtklibexplorer/RTKLIB/issues/186 + - Various fixes : #374 +### Security + - Update various python modules. + ## [2.5.0] - 2024-01-30 ### Added - udev rules to create ttyGNSS port for usb connected F9P. diff --git a/README.md b/README.md index fe507e9f..2c99c4f9 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Frontend's main features are: Other images are available in the ./images folder. ## Ready to flash release: -A ready to flash image is available for Orange Pi Zero SBC : [Armbian_RTKBase](https://github.com/Stefal/build/releases/latest) +A ready to flash image is available for Orange Pi Zero, Orange Pi Zero 2, Orange Pi Zero 3 SBC : [Armbian_RTKBase](https://github.com/Stefal/build/releases/latest) If you use a Raspberry Pi, thanks to [jancelin](https://github.com/jancelin), you can download a ready to flash iso file [here](https://github.com/jancelin/pi-gen/releases/latest). @@ -126,7 +126,9 @@ The `install.sh` script can be used without the `--all` option to split the inst -h | --help Display this help message. ``` + So, if you really want it, let's go for a manual installation with some explanations: + 1. Install dependencies with `sudo ./install.sh --dependencies`, or do it manually with: ```bash sudo apt update @@ -138,7 +140,7 @@ So, if you really want it, let's go for a manual installation with some explanat ```bash cd ~ - wget -qO - https://github.com/rtklibexplorer/RTKLIB/archive/refs/tags/b34g.tar.gz | tar -xvz + wget -qO - https://github.com/rtklibexplorer/RTKLIB/archive/refs/tags/b34j.tar.gz | tar -xvz ``` + compile and install str2str: @@ -264,6 +266,8 @@ RTKBase use several RTKLIB `str2str` instances started with `run_cast.sh` as sys The web GUI is available when the `rtkbase_web` service is running. ## Advanced: ++ Offline base station without U-Blox receiver, how to get date and time: +If gpsd can't understand the raw data from your gnss receiver, you can enable the raw2nmea service. It will convert the raw data to the tcp port set in `settings.conf` (nmea_port) and gpsd will use it to feed chrony. `systemctl enable --now rtkbase_raw2nmea` + Aerial images: The default map background is OpenStreetMap, but you can switch to a worldwide aerial layer if you have a Maptiler key. To enable this layer, create a free account on [Maptiler](https://www.maptiler.com/), create a key and add it to `settings.conf` inside the `[general]` section: `maptiler_key=your_key` @@ -276,7 +280,7 @@ If you want to install RTKBase from the dev branch, you can do it with these com cd ~ wget https://raw.githubusercontent.com/Stefal/rtkbase/dev/tools/install.sh -O install.sh chmod +x install.sh -sudo ./install.sh --alldev dev +sudo ./install.sh --all repo --rtkbase-repo dev ``` ## Other usages: @@ -296,7 +300,7 @@ A gnss receiver with a timepulse output is a very accurate [stratum 0](https://e + Set gpsd and chrony to use PPS - + gpsd: comment the `DEVICE` line in `/etc/defaut/gpsd` and uncomment `#DEVICES="tcp:\\127.0.0.1:5015 \dev\pps0` + + gpsd: comment the `DEVICE` line in `/etc/defaut/gpsd` and uncomment `#DEVICES="tcp:\\127.0.0.1:5015 \dev\pps0`. Edit the port if you use the rtkbase_raw2nmea service. + chrony: inside `/etc/chrony/chrony.conf` uncomment the refclock pps line and add noselect to the 'refclock SHM 0`. You should have something like this: ``` @@ -327,7 +331,8 @@ A gnss receiver with a timepulse output is a very accurate [stratum 0](https://e ``` ## Requirements: -Python >= 3.7 +Debian base distro >= 11 (Bullseye) +Python >= 3.8 ## History: See the [changelog](./CHANGELOG.md) diff --git a/archive_and_clean.sh b/archive_and_clean.sh index 5d85a2e2..3f5f094a 100755 --- a/archive_and_clean.sh +++ b/archive_and_clean.sh @@ -30,7 +30,7 @@ done #archive and compress previous day's gnss data. #find . -maxdepth 1 -type f -mtime -1 -mmin +60 -name "*.ubx*" -exec tar -jcvf ${archive_name} --remove-files {} +; -find . -maxdepth 1 -type f -mtime -960 -mmin +60 \( -name "*.rtcm*" -o -name "*.nov*" -o -name "*.oem*" -o -name "*.ubx*" -o -name "*.ss2*" -o -name "*.hemis*" -o -name "*.stq*" -o -name "*.javad*" -o -name "*.nvs*" -o -name "*.binex*" \) -exec zip -m9 ${archive_name} {} +; +find . -maxdepth 1 -type f -mtime -960 -mmin +60 \( -name "*.rtcm*" -o -name "*.nov*" -o -name "*.oem*" -o -name "*.ubx*" -o -name "*.ss2*" -o -name "*.hemis*" -o -name "*.stq*" -o -name "*.javad*" -o -name "*.nvs*" -o -name "*.binex*" -o -name "*.sbf*" \) -exec zip -m9 ${archive_name} {} +; #delete gnss data older than x days. #find . -maxdepth 1 -type f -name "*.tar.bz2" -mtime +${archive_rotate} -delete diff --git a/drawing/fond de panier rtkbase.FCStd b/drawing/fond de panier rtkbase.FCStd index d09955e1..1003a6b7 100644 Binary files a/drawing/fond de panier rtkbase.FCStd and b/drawing/fond de panier rtkbase.FCStd differ diff --git a/drawing/fond_de_panier__new.nc b/drawing/fond_de_panier__new.nc new file mode 100644 index 00000000..b4b7a10e --- /dev/null +++ b/drawing/fond_de_panier__new.nc @@ -0,0 +1,470 @@ +(Exported by FreeCAD) +(Post Processor: grbl_post) +(Output Time:2024-06-14 18:33:36.095746) +(Begin preamble) +G17 G90 +G21 +(Begin operation: Fixture) +(Path: Fixture) +G54 +(Finish operation: Fixture) +(Begin operation: TC: Default Tool) +(Path: TC: Default Tool) +(TC: Default Tool) +(Begin toolchange) +( M6 T1 ) +M3 S10000 +(Finish operation: TC: Default Tool) +(Begin operation: Profile) +(Path: Profile) +(Profile) +(Compensated Tool Path. Diameter: 2.0) +G0 Z7.000 +G0 X143.911 Y159.954 +G0 Z5.000 +G1 X143.911 Y159.954 Z1.800 F360.000 +G2 X144.117 Y156.101 Z1.800 I-0.411 J-1.954 K0.000 F360.000 +G2 X141.601 Y157.383 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X142.883 Y159.899 Z1.800 I1.899 J0.617 K0.000 F360.000 +G2 X143.911 Y159.954 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X143.508 Y62.997 Z7.000 +G0 X143.508 Y62.997 Z5.000 +G1 X143.508 Y62.997 Z1.800 F360.000 +G2 X144.117 Y59.101 Z1.800 I-0.008 J-1.997 K0.000 F360.000 +G2 X141.601 Y60.383 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X142.883 Y62.899 Z1.800 I1.899 J0.617 K0.000 F360.000 +G2 X143.508 Y62.997 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X29.495 Y68.405 Z7.000 +G0 X29.495 Y68.405 Z5.000 +G1 X29.495 Y68.405 Z1.800 F360.000 +G2 X28.117 Y66.601 Z1.800 I-1.995 J0.095 K0.000 F360.000 +G2 X26.883 Y70.399 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X29.495 Y68.405 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X27.541 Y163.504 Z7.000 +G0 X27.541 Y163.504 Z5.000 +G1 X27.541 Y163.504 Z1.800 F360.000 +G2 X26.883 Y167.399 Z1.800 I-0.041 J1.996 K0.000 F360.000 +G2 X29.399 Y166.117 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G2 X28.117 Y163.601 Z1.800 I-1.899 J-0.617 K0.000 F360.000 +G2 X27.541 Y163.504 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G0 Z7.000 +G0 Z7.000 +(Finish operation: Profile) +(Begin operation: Helix) +(Path: Helix) +(Helix) +(helix cut operation) +G0 Z7.000 +G0 Z7.000 +G0 X50.610 Y30.890 Z7.000 +G0 X50.610 Y30.890 Z2.000 +G0 X51.110 Y30.890 +G1 Z2.000 F360.000 +G2 X50.110 Y30.890 Z1.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z1.000 I0.500 J0.000 F360.000 +G2 X50.110 Y30.890 Z0.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z0.000 I0.500 J0.000 F360.000 +G2 X50.110 Y30.890 Z0.000 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z0.000 I0.500 J0.000 F360.000 +G0 X50.610 Y30.890 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X60.500 Y28.000 Z7.000 +G0 X60.500 Y28.000 Z2.000 +G0 X61.000 Y28.000 +G1 Z2.000 F360.000 +G2 X60.000 Y28.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z1.000 I0.500 J0.000 F360.000 +G2 X60.000 Y28.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z0.000 I0.500 J0.000 F360.000 +G2 X60.000 Y28.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z0.000 I0.500 J0.000 F360.000 +G0 X60.500 Y28.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X59.500 Y15.000 Z7.000 +G0 X59.500 Y15.000 Z2.000 +G0 X60.000 Y15.000 +G1 Z2.000 F360.000 +G2 X59.000 Y15.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z1.000 I0.500 J0.000 F360.000 +G2 X59.000 Y15.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G2 X59.000 Y15.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G0 X59.500 Y15.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y15.000 Z7.000 +G0 X70.500 Y15.000 Z2.000 +G0 X71.000 Y15.000 +G1 Z2.000 F360.000 +G2 X70.000 Y15.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y15.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y15.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y15.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X93.500 Y15.000 Z7.000 +G0 X93.500 Y15.000 Z2.000 +G0 X94.000 Y15.000 +G1 Z2.000 F360.000 +G2 X93.000 Y15.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y15.000 Z1.000 I0.500 J0.000 F360.000 +G2 X93.000 Y15.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G2 X93.000 Y15.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X94.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G0 X93.500 Y15.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X115.000 Y68.100 Z7.000 +G0 X115.000 Y68.100 Z2.000 +G0 X115.500 Y68.100 +G1 Z2.000 F360.000 +G2 X114.500 Y68.100 Z1.500 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z1.000 I0.500 J0.000 F360.000 +G2 X114.500 Y68.100 Z0.500 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z0.000 I0.500 J0.000 F360.000 +G2 X114.500 Y68.100 Z0.000 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z0.000 I0.500 J0.000 F360.000 +G0 X115.000 Y68.100 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X93.500 Y73.000 Z7.000 +G0 X93.500 Y73.000 Z2.000 +G0 X94.000 Y73.000 +G1 Z2.000 F360.000 +G2 X93.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X93.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X93.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X93.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y73.000 Z7.000 +G0 X70.500 Y73.000 Z2.000 +G0 X71.000 Y73.000 +G1 Z2.000 F360.000 +G2 X70.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X50.610 Y73.000 Z7.000 +G0 X50.610 Y73.000 Z2.000 +G0 X51.110 Y73.000 +G1 Z2.000 F360.000 +G2 X50.110 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X50.110 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X50.110 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X50.610 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y68.500 Z7.000 +G0 X27.500 Y68.500 Z2.000 +G0 X28.000 Y68.500 +G1 Z2.000 F360.000 +G2 X27.000 Y68.500 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y68.500 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y68.500 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y68.500 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X10.500 Y73.000 Z7.000 +G0 X10.500 Y73.000 Z2.000 +G0 X11.000 Y73.000 +G1 Z2.000 F360.000 +G2 X10.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X10.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X10.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X10.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y106.080 Z7.000 +G0 X27.500 Y106.080 Z2.000 +G0 X28.000 Y106.080 +G1 Z2.000 F360.000 +G2 X27.000 Y106.080 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y106.080 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y106.080 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y106.080 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y143.868 Z7.000 +G0 X27.500 Y143.868 Z2.000 +G0 X28.000 Y143.868 +G1 Z2.000 F360.000 +G2 X27.000 Y143.868 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y143.868 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y143.868 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y143.868 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y165.500 Z7.000 +G0 X27.500 Y165.500 Z2.000 +G0 X28.000 Y165.500 +G1 Z2.000 F360.000 +G2 X27.000 Y165.500 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y165.500 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y165.500 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y165.500 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X82.500 Y166.300 Z7.000 +G0 X82.500 Y166.300 Z2.000 +G0 X83.000 Y166.300 +G1 Z2.000 F360.000 +G2 X82.000 Y166.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z1.000 I0.500 J0.000 F360.000 +G2 X82.000 Y166.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G2 X82.000 Y166.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G0 X82.500 Y166.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X82.500 Y121.300 Z7.000 +G0 X82.500 Y121.300 Z2.000 +G0 X83.000 Y121.300 +G1 Z2.000 F360.000 +G2 X82.000 Y121.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z1.000 I0.500 J0.000 F360.000 +G2 X82.000 Y121.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G2 X82.000 Y121.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G0 X82.500 Y121.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y106.080 Z7.000 +G0 X70.500 Y106.080 Z2.000 +G0 X71.000 Y106.080 +G1 Z2.000 F360.000 +G2 X70.000 Y106.080 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y106.080 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y106.080 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y106.080 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X127.500 Y121.300 Z7.000 +G0 X127.500 Y121.300 Z2.000 +G0 X128.000 Y121.300 +G1 Z2.000 F360.000 +G2 X127.000 Y121.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z1.000 I0.500 J0.000 F360.000 +G2 X127.000 Y121.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G2 X127.000 Y121.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G0 X127.500 Y121.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X143.500 Y158.000 Z7.000 +G0 X143.500 Y158.000 Z2.000 +G0 X144.000 Y158.000 +G1 Z2.000 F360.000 +G2 X143.000 Y158.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z1.000 I0.500 J0.000 F360.000 +G2 X143.000 Y158.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z0.000 I0.500 J0.000 F360.000 +G2 X143.000 Y158.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z0.000 I0.500 J0.000 F360.000 +G0 X143.500 Y158.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X127.500 Y166.300 Z7.000 +G0 X127.500 Y166.300 Z2.000 +G0 X128.000 Y166.300 +G1 Z2.000 F360.000 +G2 X127.000 Y166.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z1.000 I0.500 J0.000 F360.000 +G2 X127.000 Y166.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G2 X127.000 Y166.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G0 X127.500 Y166.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X187.000 Y79.000 Z7.000 +G0 X187.000 Y79.000 Z2.000 +G0 X187.500 Y79.000 +G1 Z2.000 F360.000 +G2 X186.500 Y79.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z1.000 I0.500 J0.000 F360.000 +G2 X186.500 Y79.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z0.000 I0.500 J0.000 F360.000 +G2 X186.500 Y79.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z0.000 I0.500 J0.000 F360.000 +G0 X187.000 Y79.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X143.500 Y61.000 Z7.000 +G0 X143.500 Y61.000 Z2.000 +G0 X144.000 Y61.000 +G1 Z2.000 F360.000 +G2 X143.000 Y61.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z1.000 I0.500 J0.000 F360.000 +G2 X143.000 Y61.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z0.000 I0.500 J0.000 F360.000 +G2 X143.000 Y61.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z0.000 I0.500 J0.000 F360.000 +G0 X143.500 Y61.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +(Finish operation: Helix) +(Begin operation: Pocket_Shape) +(Path: Pocket_Shape) +(Pocket_Shape) +G0 Z7.000 +G0 X60.842 Y73.359 +G0 Z5.000 +G1 X60.842 Y73.359 Z1.000 F360.000 +G2 X60.897 Y72.706 Z1.000 I-0.359 J-0.359 K0.000 F360.000 +G2 X60.542 Y72.507 Z1.000 I-0.397 J0.294 K0.000 F360.000 +G3 X59.883 Y72.579 Z1.000 I-0.669 J-3.087 K0.000 F360.000 +G2 X59.355 Y72.527 Z1.000 I-0.348 J0.835 K0.000 F360.000 +G2 X59.563 Y73.490 Z1.000 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z1.000 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z1.000 I0.252 J-0.441 K0.000 F360.000 +G1 X60.842 Y73.359 Z0.200 F360.000 +G2 X60.897 Y72.706 Z0.200 I-0.359 J-0.359 K0.000 F360.000 +G2 X60.542 Y72.507 Z0.200 I-0.397 J0.294 K0.000 F360.000 +G3 X59.883 Y72.579 Z0.200 I-0.669 J-3.087 K0.000 F360.000 +G2 X59.355 Y72.527 Z0.200 I-0.348 J0.835 K0.000 F360.000 +G2 X59.563 Y73.490 Z0.200 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z0.200 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z0.200 I0.252 J-0.441 K0.000 F360.000 +G1 X60.842 Y73.359 Z0.000 F360.000 +G2 X60.897 Y72.706 Z0.000 I-0.359 J-0.359 K-0.000 F360.000 +G2 X60.542 Y72.507 Z0.000 I-0.397 J0.294 K-0.000 F360.000 +G3 X59.883 Y72.579 Z-0.000 I-0.669 J-3.087 K-0.000 F360.000 +G2 X59.355 Y72.527 Z-0.000 I-0.348 J0.835 K-0.000 F360.000 +G2 X59.563 Y73.490 Z-0.000 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z0.000 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z0.000 I0.252 J-0.441 K0.000 F360.000 +G0 Z7.000 +G0 Z7.000 +(Finish operation: Pocket_Shape) +(Begin operation: DressupTag) +(Path: DressupTag) +G0 Z7.000 +G0 X193.014 Y155.500 Z7.000 +G0 X193.014 Y155.500 Z5.000 +G1 X193.014 Y155.500 Z0.500 F360.000 +G3 X193.000 Y155.500 Z0.500 I-0.014 J-0.500 K0.000 F360.000 +G1 X184.008 Y155.500 Z0.500 F360.000 +G2 X166.500 Y173.016 Z0.500 I-0.007 J17.501 K0.000 F360.000 +G3 X166.000 Y173.500 Z0.500 I-0.500 J-0.016 K0.000 F360.000 +G1 X102.140 Y173.500 Z0.500 F360.000 +G1 X101.640 Y173.500 Z1.000 F360.000 +G1 X87.360 Y173.500 Z1.000 F360.000 +G1 X86.860 Y173.500 Z0.500 F360.000 +G1 X23.000 Y173.500 Z0.500 F360.000 +G3 X22.500 Y173.016 Z0.500 I-0.000 J-0.500 K0.000 F360.000 +G2 X4.984 Y155.500 Z0.500 I-17.502 J-0.015 K0.000 F360.000 +G3 X4.500 Y155.000 Z0.500 I0.016 J-0.500 K0.000 F360.000 +G1 X4.500 Y115.140 Z0.500 F360.000 +G1 X4.500 Y114.640 Z1.000 F360.000 +G1 X4.500 Y100.360 Z1.000 F360.000 +G1 X4.500 Y99.860 Z0.500 F360.000 +G1 X4.500 Y60.000 Z0.500 F360.000 +G3 X5.000 Y59.500 Z0.500 I0.500 J-0.000 K0.000 F360.000 +G1 X16.990 Y59.500 Z0.500 F360.000 +G2 X28.500 Y47.990 Z0.500 I0.009 J-11.501 K0.000 F360.000 +G1 X28.500 Y5.000 Z0.500 F360.000 +G3 X29.000 Y4.500 Z0.500 I0.500 J-0.000 K0.000 F360.000 +G1 X91.360 Y4.500 Z0.500 F360.000 +G1 X91.860 Y4.500 Z1.000 F360.000 +G1 X106.140 Y4.500 Z1.000 F360.000 +G1 X106.640 Y4.500 Z0.500 F360.000 +G1 X169.000 Y4.500 Z0.500 F360.000 +G3 X169.500 Y5.000 Z0.500 I0.000 J0.500 K0.000 F360.000 +G1 X169.500 Y47.990 Z0.500 F360.000 +G2 X181.010 Y59.500 Z0.500 I11.501 J0.009 K0.000 F360.000 +G1 X193.000 Y59.500 Z0.500 F360.000 +G3 X193.500 Y60.000 Z0.500 I0.000 J0.500 K0.000 F360.000 +G1 X193.500 Y99.860 Z0.500 F360.000 +G1 X193.500 Y100.360 Z1.000 F360.000 +G1 X193.500 Y114.640 Z1.000 F360.000 +G1 X193.500 Y115.140 Z0.500 F360.000 +G1 X193.500 Y155.000 Z0.500 F360.000 +G3 X193.014 Y155.500 Z0.500 I-0.500 J0.000 K0.000 F360.000 +G1 X193.014 Y155.500 Z0.000 F360.000 +G3 X193.000 Y155.500 Z0.000 I-0.014 J-0.500 K0.000 F360.000 +G1 X184.008 Y155.500 Z0.000 F360.000 +G2 X166.500 Y173.016 Z0.000 I-0.007 J17.501 K0.000 F360.000 +G3 X166.000 Y173.500 Z0.000 I-0.500 J-0.016 K0.000 F360.000 +G1 X102.640 Y173.500 Z0.000 F360.000 +G1 X101.640 Y173.500 Z1.000 F360.000 +G1 X87.360 Y173.500 Z1.000 F360.000 +G1 X86.360 Y173.500 Z0.000 F360.000 +G1 X23.000 Y173.500 Z0.000 F360.000 +G3 X22.500 Y173.016 Z0.000 I-0.000 J-0.500 K0.000 F360.000 +G2 X4.984 Y155.500 Z0.000 I-17.502 J-0.015 K0.000 F360.000 +G3 X4.500 Y155.000 Z0.000 I0.016 J-0.500 K0.000 F360.000 +G1 X4.500 Y115.640 Z0.000 F360.000 +G1 X4.500 Y114.640 Z1.000 F360.000 +G1 X4.500 Y100.360 Z1.000 F360.000 +G1 X4.500 Y99.360 Z0.000 F360.000 +G1 X4.500 Y60.000 Z0.000 F360.000 +G3 X5.000 Y59.500 Z0.000 I0.500 J-0.000 K0.000 F360.000 +G1 X16.990 Y59.500 Z0.000 F360.000 +G2 X28.500 Y47.990 Z0.000 I0.009 J-11.501 K0.000 F360.000 +G1 X28.500 Y5.000 Z0.000 F360.000 +G3 X29.000 Y4.500 Z0.000 I0.500 J-0.000 K0.000 F360.000 +G1 X90.860 Y4.500 Z0.000 F360.000 +G1 X91.860 Y4.500 Z1.000 F360.000 +G1 X106.140 Y4.500 Z1.000 F360.000 +G1 X107.140 Y4.500 Z0.000 F360.000 +G1 X169.000 Y4.500 Z0.000 F360.000 +G3 X169.500 Y5.000 Z0.000 I0.000 J0.500 K0.000 F360.000 +G1 X169.500 Y47.990 Z0.000 F360.000 +G2 X181.010 Y59.500 Z0.000 I11.501 J0.009 K0.000 F360.000 +G1 X193.000 Y59.500 Z0.000 F360.000 +G3 X193.500 Y60.000 Z0.000 I0.000 J0.500 K0.000 F360.000 +G1 X193.500 Y99.360 Z0.000 F360.000 +G1 X193.500 Y100.360 Z1.000 F360.000 +G1 X193.500 Y114.640 Z1.000 F360.000 +G1 X193.500 Y115.640 Z0.000 F360.000 +G1 X193.500 Y155.000 Z0.000 F360.000 +G3 X193.014 Y155.500 Z0.000 I-0.500 J0.000 K0.000 F360.000 +G0 X193.014 Y155.500 Z7.000 +(Finish operation: DressupTag) +(Begin postamble) +M5 +G17 G90 +M2 diff --git a/drawing/plane.nc b/drawing/plane.nc index 61a8026b..234965f1 100644 --- a/drawing/plane.nc +++ b/drawing/plane.nc @@ -1,414 +1,468 @@ (Exported by FreeCAD) (Post Processor: grbl_post) -(Output Time:2023-07-19 18:34:42.746542) +(Output Time:2024-05-22 18:41:59.392062) (Begin preamble) G17 G90 G21 -(Begin operation: G54) -(Path: G54) +(Begin operation: Fixture) +(Path: Fixture) G54 -G0 Z5.000 -(Finish operation: G54) -(Begin operation: Default Tool) -(Path: Default Tool) -(Default Tool) +(Finish operation: Fixture) +(Begin operation: TC: Default Tool) +(Path: TC: Default Tool) +(TC: Default Tool) (Begin toolchange) ( M6 T1 ) M3 S10000 -(Finish operation: Default Tool) -(Begin operation: Profile001) -(Path: Profile001) -(Profile001) +(Finish operation: TC: Default Tool) +(Begin operation: Profile) +(Path: Profile) +(Profile) (Compensated Tool Path. Diameter: 2.0) -G0 Z5.000 -G0 X28.912 Y69.912 -G0 Z3.000 -G1 X28.912 Y69.912 Z-0.200 F360.000 -G2 X28.117 Y66.601 Z-0.200 I-1.412 J-1.412 K0.000 F360.000 -G2 X26.883 Y70.399 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G2 X28.912 Y69.912 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X28.912 Y69.912 -G0 X27.529 Y163.503 -G0 X27.529 Y163.503 Z3.000 -G1 X27.529 Y163.503 Z-0.200 F360.000 -G2 X26.883 Y167.399 Z-0.200 I-0.029 J1.997 K0.000 F360.000 -G2 X28.117 Y163.601 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G2 X27.529 Y163.503 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X27.529 Y163.503 -G0 X141.505 Y158.095 -G0 X141.505 Y158.095 Z3.000 -G1 X141.505 Y158.095 Z-0.200 F360.000 -G2 X142.883 Y159.899 Z-0.200 I1.995 J-0.095 K0.000 F360.000 -G2 X144.117 Y156.101 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G2 X141.505 Y158.095 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X141.505 Y158.095 -G0 X143.459 Y62.996 -G0 X143.459 Y62.996 Z3.000 -G1 X143.459 Y62.996 Z-0.200 F360.000 -G2 X144.117 Y59.101 Z-0.200 I0.041 J-1.996 K0.000 F360.000 -G2 X141.601 Y60.383 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G2 X142.883 Y62.899 Z-0.200 I1.899 J0.617 K0.000 F360.000 -G2 X143.459 Y62.996 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -(Finish operation: Profile001) -(Begin operation: Helix001) -(Path: Helix001) -(Helix001) +G0 Z7.000 +G0 X143.911 Y159.954 +G0 Z5.000 +G1 X143.911 Y159.954 Z1.800 F360.000 +G2 X144.117 Y156.101 Z1.800 I-0.411 J-1.954 K0.000 F360.000 +G2 X141.601 Y157.383 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X142.883 Y159.899 Z1.800 I1.899 J0.617 K0.000 F360.000 +G2 X143.911 Y159.954 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X143.508 Y62.997 Z7.000 +G0 X143.508 Y62.997 Z5.000 +G1 X143.508 Y62.997 Z1.800 F360.000 +G2 X144.117 Y59.101 Z1.800 I-0.008 J-1.997 K0.000 F360.000 +G2 X141.601 Y60.383 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X142.883 Y62.899 Z1.800 I1.899 J0.617 K0.000 F360.000 +G2 X143.508 Y62.997 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X29.495 Y68.405 Z7.000 +G0 X29.495 Y68.405 Z5.000 +G1 X29.495 Y68.405 Z1.800 F360.000 +G2 X28.117 Y66.601 Z1.800 I-1.995 J0.095 K0.000 F360.000 +G2 X26.883 Y70.399 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G2 X29.495 Y68.405 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G0 Z7.000 +G0 X27.541 Y163.504 Z7.000 +G0 X27.541 Y163.504 Z5.000 +G1 X27.541 Y163.504 Z1.800 F360.000 +G2 X26.883 Y167.399 Z1.800 I-0.041 J1.996 K0.000 F360.000 +G2 X29.399 Y166.117 Z1.800 I0.617 J-1.899 K0.000 F360.000 +G2 X28.117 Y163.601 Z1.800 I-1.899 J-0.617 K0.000 F360.000 +G2 X27.541 Y163.504 Z1.800 I-0.617 J1.899 K0.000 F360.000 +G0 Z7.000 +G0 Z7.000 +(Finish operation: Profile) +(Begin operation: Helix) +(Path: Helix) +(Helix) (helix cut operation) -G0 Z5.000 -G0 Z5.000 -G0 X50.610 Y30.890 Z5.000 -G0 X50.610 Y30.890 Z0.000 +G0 Z7.000 +G0 Z7.000 +G0 X50.610 Y30.890 Z7.000 +G0 X50.610 Y30.890 Z2.000 G0 X51.110 Y30.890 -G1 Z0.000 F360.000 -G2 X50.110 Y30.890 Z-0.550 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-1.100 I0.500 J0.000 F360.000 -G2 X50.110 Y30.890 Z-1.650 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-2.200 I0.500 J0.000 F360.000 -G2 X50.110 Y30.890 Z-2.200 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-2.200 I0.500 J0.000 F360.000 -G0 X50.610 Y30.890 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X59.500 Y15.000 Z5.000 -G0 X59.500 Y15.000 Z0.000 +G1 Z2.000 F360.000 +G2 X50.110 Y30.890 Z1.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z1.000 I0.500 J0.000 F360.000 +G2 X50.110 Y30.890 Z0.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z0.000 I0.500 J0.000 F360.000 +G2 X50.110 Y30.890 Z0.000 I-0.500 J0.000 F360.000 +G2 X51.110 Y30.890 Z0.000 I0.500 J0.000 F360.000 +G0 X50.610 Y30.890 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X60.500 Y28.000 Z7.000 +G0 X60.500 Y28.000 Z2.000 +G0 X61.000 Y28.000 +G1 Z2.000 F360.000 +G2 X60.000 Y28.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z1.000 I0.500 J0.000 F360.000 +G2 X60.000 Y28.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z0.000 I0.500 J0.000 F360.000 +G2 X60.000 Y28.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X61.000 Y28.000 Z0.000 I0.500 J0.000 F360.000 +G0 X60.500 Y28.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X59.500 Y15.000 Z7.000 +G0 X59.500 Y15.000 Z2.000 G0 X60.000 Y15.000 -G1 Z0.000 F360.000 -G2 X59.000 Y15.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X59.000 Y15.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X59.000 Y15.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X59.500 Y15.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X68.706 Y15.000 Z5.000 -G0 X68.706 Y15.000 Z0.000 -G0 X69.206 Y15.000 -G1 Z0.000 F360.000 -G2 X68.206 Y15.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X69.206 Y15.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X68.206 Y15.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X69.206 Y15.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X68.206 Y15.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X69.206 Y15.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X68.706 Y15.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X68.706 Y73.000 Z5.000 -G0 X68.706 Y73.000 Z0.000 -G0 X69.206 Y73.000 -G1 Z0.000 F360.000 -G2 X68.206 Y73.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X69.206 Y73.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X68.206 Y73.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X69.206 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X68.206 Y73.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X69.206 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X68.706 Y73.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X59.500 Y73.000 Z5.000 -G0 X59.500 Y73.000 Z0.000 -G0 X60.000 Y73.000 -G1 Z0.000 F360.000 -G2 X59.000 Y73.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X59.000 Y73.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X59.000 Y73.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X59.500 Y73.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X50.610 Y73.000 Z5.000 -G0 X50.610 Y73.000 Z0.000 +G1 Z2.000 F360.000 +G2 X59.000 Y15.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z1.000 I0.500 J0.000 F360.000 +G2 X59.000 Y15.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G2 X59.000 Y15.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X60.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G0 X59.500 Y15.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y15.000 Z7.000 +G0 X70.500 Y15.000 Z2.000 +G0 X71.000 Y15.000 +G1 Z2.000 F360.000 +G2 X70.000 Y15.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y15.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y15.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y15.000 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y15.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X93.500 Y16.165 Z7.000 +G0 X93.500 Y16.165 Z2.000 +G0 X94.000 Y16.165 +G1 Z2.000 F360.000 +G2 X93.000 Y16.165 Z1.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y16.165 Z1.000 I0.500 J0.000 F360.000 +G2 X93.000 Y16.165 Z0.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y16.165 Z0.000 I0.500 J0.000 F360.000 +G2 X93.000 Y16.165 Z0.000 I-0.500 J0.000 F360.000 +G2 X94.000 Y16.165 Z0.000 I0.500 J0.000 F360.000 +G0 X93.500 Y16.165 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X115.000 Y68.100 Z7.000 +G0 X115.000 Y68.100 Z2.000 +G0 X115.500 Y68.100 +G1 Z2.000 F360.000 +G2 X114.500 Y68.100 Z1.500 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z1.000 I0.500 J0.000 F360.000 +G2 X114.500 Y68.100 Z0.500 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z0.000 I0.500 J0.000 F360.000 +G2 X114.500 Y68.100 Z0.000 I-0.500 J0.000 F360.000 +G2 X115.500 Y68.100 Z0.000 I0.500 J0.000 F360.000 +G0 X115.000 Y68.100 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X93.500 Y73.000 Z7.000 +G0 X93.500 Y73.000 Z2.000 +G0 X94.000 Y73.000 +G1 Z2.000 F360.000 +G2 X93.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X93.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X93.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X94.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X93.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y73.000 Z7.000 +G0 X70.500 Y73.000 Z2.000 +G0 X71.000 Y73.000 +G1 Z2.000 F360.000 +G2 X70.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X50.610 Y73.000 Z7.000 +G0 X50.610 Y73.000 Z2.000 G0 X51.110 Y73.000 -G1 Z0.000 F360.000 -G2 X50.110 Y73.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X50.110 Y73.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X50.110 Y73.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X50.610 Y73.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X27.500 Y68.500 Z5.000 -G0 X27.500 Y68.500 Z0.000 +G1 Z2.000 F360.000 +G2 X50.110 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X50.110 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X50.110 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X51.110 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X50.610 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y68.500 Z7.000 +G0 X27.500 Y68.500 Z2.000 G0 X28.000 Y68.500 -G1 Z0.000 F360.000 -G2 X27.000 Y68.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X27.000 Y68.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X27.000 Y68.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X27.500 Y68.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X10.500 Y73.000 Z5.000 -G0 X10.500 Y73.000 Z0.000 +G1 Z2.000 F360.000 +G2 X27.000 Y68.500 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y68.500 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y68.500 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y68.500 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y68.500 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X10.500 Y73.000 Z7.000 +G0 X10.500 Y73.000 Z2.000 G0 X11.000 Y73.000 -G1 Z0.000 F360.000 -G2 X10.000 Y73.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X10.000 Y73.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X10.000 Y73.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X10.500 Y73.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X27.500 Y106.080 Z5.000 -G0 X27.500 Y106.080 Z0.000 +G1 Z2.000 F360.000 +G2 X10.000 Y73.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z1.000 I0.500 J0.000 F360.000 +G2 X10.000 Y73.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G2 X10.000 Y73.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X11.000 Y73.000 Z0.000 I0.500 J0.000 F360.000 +G0 X10.500 Y73.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y106.080 Z7.000 +G0 X27.500 Y106.080 Z2.000 G0 X28.000 Y106.080 -G1 Z0.000 F360.000 -G2 X27.000 Y106.080 Z-0.550 I-0.500 J0.000 F360.000 -G2 X28.000 Y106.080 Z-1.100 I0.500 J0.000 F360.000 -G2 X27.000 Y106.080 Z-1.650 I-0.500 J0.000 F360.000 -G2 X28.000 Y106.080 Z-2.200 I0.500 J0.000 F360.000 -G2 X27.000 Y106.080 Z-2.200 I-0.500 J0.000 F360.000 -G2 X28.000 Y106.080 Z-2.200 I0.500 J0.000 F360.000 -G0 X27.500 Y106.080 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X27.500 Y143.868 Z5.000 -G0 X27.500 Y143.868 Z0.000 +G1 Z2.000 F360.000 +G2 X27.000 Y106.080 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y106.080 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y106.080 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y106.080 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y143.868 Z7.000 +G0 X27.500 Y143.868 Z2.000 G0 X28.000 Y143.868 -G1 Z0.000 F360.000 -G2 X27.000 Y143.868 Z-0.550 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-1.100 I0.500 J0.000 F360.000 -G2 X27.000 Y143.868 Z-1.650 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-2.200 I0.500 J0.000 F360.000 -G2 X27.000 Y143.868 Z-2.200 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-2.200 I0.500 J0.000 F360.000 -G0 X27.500 Y143.868 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X27.500 Y165.500 Z5.000 -G0 X27.500 Y165.500 Z0.000 +G1 Z2.000 F360.000 +G2 X27.000 Y143.868 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y143.868 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y143.868 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y143.868 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y143.868 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X27.500 Y165.500 Z7.000 +G0 X27.500 Y165.500 Z2.000 G0 X28.000 Y165.500 -G1 Z0.000 F360.000 -G2 X27.000 Y165.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X27.000 Y165.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X27.000 Y165.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X27.500 Y165.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X82.500 Y166.500 Z5.000 -G0 X82.500 Y166.500 Z0.000 -G0 X83.000 Y166.500 -G1 Z0.000 F360.000 -G2 X82.000 Y166.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X82.000 Y166.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X82.000 Y166.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X82.500 Y166.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X82.500 Y121.500 Z5.000 -G0 X82.500 Y121.500 Z0.000 -G0 X83.000 Y121.500 -G1 Z0.000 F360.000 -G2 X82.000 Y121.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X82.000 Y121.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X82.000 Y121.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X82.500 Y121.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X68.706 Y106.080 Z5.000 -G0 X68.706 Y106.080 Z0.000 -G0 X69.206 Y106.080 -G1 Z0.000 F360.000 -G2 X68.206 Y106.080 Z-0.550 I-0.500 J0.000 F360.000 -G2 X69.206 Y106.080 Z-1.100 I0.500 J0.000 F360.000 -G2 X68.206 Y106.080 Z-1.650 I-0.500 J0.000 F360.000 -G2 X69.206 Y106.080 Z-2.200 I0.500 J0.000 F360.000 -G2 X68.206 Y106.080 Z-2.200 I-0.500 J0.000 F360.000 -G2 X69.206 Y106.080 Z-2.200 I0.500 J0.000 F360.000 -G0 X68.706 Y106.080 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X115.000 Y68.100 Z5.000 -G0 X115.000 Y68.100 Z0.000 -G0 X115.500 Y68.100 -G1 Z0.000 F360.000 -G2 X114.500 Y68.100 Z-0.550 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-1.100 I0.500 J0.000 F360.000 -G2 X114.500 Y68.100 Z-1.650 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-2.200 I0.500 J0.000 F360.000 -G2 X114.500 Y68.100 Z-2.200 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-2.200 I0.500 J0.000 F360.000 -G0 X115.000 Y68.100 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X143.500 Y61.000 Z5.000 -G0 X143.500 Y61.000 Z0.000 -G0 X144.000 Y61.000 -G1 Z0.000 F360.000 -G2 X143.000 Y61.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X143.000 Y61.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X143.000 Y61.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X143.500 Y61.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X187.000 Y79.000 Z5.000 -G0 X187.000 Y79.000 Z0.000 -G0 X187.500 Y79.000 -G1 Z0.000 F360.000 -G2 X186.500 Y79.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X186.500 Y79.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X186.500 Y79.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X187.000 Y79.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X127.500 Y121.500 Z5.000 -G0 X127.500 Y121.500 Z0.000 -G0 X128.000 Y121.500 -G1 Z0.000 F360.000 -G2 X127.000 Y121.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X127.000 Y121.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X127.000 Y121.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X127.500 Y121.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X143.500 Y158.000 Z5.000 -G0 X143.500 Y158.000 Z0.000 +G1 Z2.000 F360.000 +G2 X27.000 Y165.500 Z1.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z1.000 I0.500 J0.000 F360.000 +G2 X27.000 Y165.500 Z0.500 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z0.000 I0.500 J0.000 F360.000 +G2 X27.000 Y165.500 Z0.000 I-0.500 J0.000 F360.000 +G2 X28.000 Y165.500 Z0.000 I0.500 J0.000 F360.000 +G0 X27.500 Y165.500 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X82.500 Y166.300 Z7.000 +G0 X82.500 Y166.300 Z2.000 +G0 X83.000 Y166.300 +G1 Z2.000 F360.000 +G2 X82.000 Y166.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z1.000 I0.500 J0.000 F360.000 +G2 X82.000 Y166.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G2 X82.000 Y166.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X83.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G0 X82.500 Y166.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X82.500 Y121.300 Z7.000 +G0 X82.500 Y121.300 Z2.000 +G0 X83.000 Y121.300 +G1 Z2.000 F360.000 +G2 X82.000 Y121.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z1.000 I0.500 J0.000 F360.000 +G2 X82.000 Y121.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G2 X82.000 Y121.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X83.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G0 X82.500 Y121.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X70.500 Y106.080 Z7.000 +G0 X70.500 Y106.080 Z2.000 +G0 X71.000 Y106.080 +G1 Z2.000 F360.000 +G2 X70.000 Y106.080 Z1.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z1.000 I0.500 J0.000 F360.000 +G2 X70.000 Y106.080 Z0.500 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G2 X70.000 Y106.080 Z0.000 I-0.500 J0.000 F360.000 +G2 X71.000 Y106.080 Z0.000 I0.500 J0.000 F360.000 +G0 X70.500 Y106.080 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X127.500 Y121.300 Z7.000 +G0 X127.500 Y121.300 Z2.000 +G0 X128.000 Y121.300 +G1 Z2.000 F360.000 +G2 X127.000 Y121.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z1.000 I0.500 J0.000 F360.000 +G2 X127.000 Y121.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G2 X127.000 Y121.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X128.000 Y121.300 Z0.000 I0.500 J0.000 F360.000 +G0 X127.500 Y121.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X143.500 Y158.000 Z7.000 +G0 X143.500 Y158.000 Z2.000 G0 X144.000 Y158.000 -G1 Z0.000 F360.000 -G2 X143.000 Y158.000 Z-0.550 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-1.100 I0.500 J0.000 F360.000 -G2 X143.000 Y158.000 Z-1.650 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-2.200 I0.500 J0.000 F360.000 -G2 X143.000 Y158.000 Z-2.200 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-2.200 I0.500 J0.000 F360.000 -G0 X143.500 Y158.000 Z-2.200 -G0 Z0.000 -G0 Z5.000 -G0 X127.500 Y166.500 Z5.000 -G0 X127.500 Y166.500 Z0.000 -G0 X128.000 Y166.500 -G1 Z0.000 F360.000 -G2 X127.000 Y166.500 Z-0.550 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-1.100 I0.500 J0.000 F360.000 -G2 X127.000 Y166.500 Z-1.650 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-2.200 I0.500 J0.000 F360.000 -G2 X127.000 Y166.500 Z-2.200 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-2.200 I0.500 J0.000 F360.000 -G0 X127.500 Y166.500 Z-2.200 -G0 Z0.000 -G0 Z5.000 -(Finish operation: Helix001) +G1 Z2.000 F360.000 +G2 X143.000 Y158.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z1.000 I0.500 J0.000 F360.000 +G2 X143.000 Y158.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z0.000 I0.500 J0.000 F360.000 +G2 X143.000 Y158.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X144.000 Y158.000 Z0.000 I0.500 J0.000 F360.000 +G0 X143.500 Y158.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X127.500 Y166.300 Z7.000 +G0 X127.500 Y166.300 Z2.000 +G0 X128.000 Y166.300 +G1 Z2.000 F360.000 +G2 X127.000 Y166.300 Z1.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z1.000 I0.500 J0.000 F360.000 +G2 X127.000 Y166.300 Z0.500 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G2 X127.000 Y166.300 Z0.000 I-0.500 J0.000 F360.000 +G2 X128.000 Y166.300 Z0.000 I0.500 J0.000 F360.000 +G0 X127.500 Y166.300 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X187.000 Y79.000 Z7.000 +G0 X187.000 Y79.000 Z2.000 +G0 X187.500 Y79.000 +G1 Z2.000 F360.000 +G2 X186.500 Y79.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z1.000 I0.500 J0.000 F360.000 +G2 X186.500 Y79.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z0.000 I0.500 J0.000 F360.000 +G2 X186.500 Y79.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X187.500 Y79.000 Z0.000 I0.500 J0.000 F360.000 +G0 X187.000 Y79.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +G0 X143.500 Y61.000 Z7.000 +G0 X143.500 Y61.000 Z2.000 +G0 X144.000 Y61.000 +G1 Z2.000 F360.000 +G2 X143.000 Y61.000 Z1.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z1.000 I0.500 J0.000 F360.000 +G2 X143.000 Y61.000 Z0.500 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z0.000 I0.500 J0.000 F360.000 +G2 X143.000 Y61.000 Z0.000 I-0.500 J0.000 F360.000 +G2 X144.000 Y61.000 Z0.000 I0.500 J0.000 F360.000 +G0 X143.500 Y61.000 Z0.000 +G0 Z2.000 +G0 Z7.000 +(Finish operation: Helix) +(Begin operation: Pocket_Shape) +(Path: Pocket_Shape) +(Pocket_Shape) +G0 Z7.000 +G0 X60.842 Y73.359 +G0 Z5.000 +G1 X60.842 Y73.359 Z1.000 F360.000 +G2 X60.897 Y72.706 Z1.000 I-0.359 J-0.359 K0.000 F360.000 +G2 X60.542 Y72.507 Z1.000 I-0.397 J0.294 K0.000 F360.000 +G3 X59.883 Y72.579 Z1.000 I-0.669 J-3.087 K0.000 F360.000 +G2 X59.355 Y72.527 Z1.000 I-0.348 J0.835 K0.000 F360.000 +G2 X59.563 Y73.490 Z1.000 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z1.000 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z1.000 I0.252 J-0.441 K0.000 F360.000 +G1 X60.842 Y73.359 Z0.200 F360.000 +G2 X60.897 Y72.706 Z0.200 I-0.359 J-0.359 K0.000 F360.000 +G2 X60.542 Y72.507 Z0.200 I-0.397 J0.294 K0.000 F360.000 +G3 X59.883 Y72.579 Z0.200 I-0.669 J-3.087 K0.000 F360.000 +G2 X59.355 Y72.527 Z0.200 I-0.348 J0.835 K0.000 F360.000 +G2 X59.563 Y73.490 Z0.200 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z0.200 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z0.200 I0.252 J-0.441 K0.000 F360.000 +G1 X60.842 Y73.359 Z0.000 F360.000 +G2 X60.897 Y72.706 Z0.000 I-0.359 J-0.359 K-0.000 F360.000 +G2 X60.542 Y72.507 Z0.000 I-0.397 J0.294 K-0.000 F360.000 +G3 X59.883 Y72.579 Z-0.000 I-0.669 J-3.087 K-0.000 F360.000 +G2 X59.355 Y72.527 Z-0.000 I-0.348 J0.835 K-0.000 F360.000 +G2 X59.563 Y73.490 Z-0.000 I0.145 J0.473 K0.000 F360.000 +G3 X60.232 Y73.441 Z0.000 I0.422 J1.177 K0.000 F360.000 +G2 X60.842 Y73.359 Z0.000 I0.252 J-0.441 K0.000 F360.000 +G0 Z7.000 +G0 Z7.000 +(Finish operation: Pocket_Shape) (Begin operation: DressupTag) (Path: DressupTag) -G0 Z5.000 -G0 X193.014 Y155.500 Z5.000 -G0 X193.014 Y155.500 Z3.000 -G1 X193.014 Y155.500 Z-1.500 F360.000 -G3 X193.000 Y155.500 Z-1.500 I-0.014 J-0.500 K0.000 F360.000 -G1 X184.008 Y155.500 Z-1.500 F360.000 -G2 X166.500 Y173.016 Z-1.500 I-0.007 J17.501 K0.000 F360.000 -G3 X166.000 Y173.500 Z-1.500 I-0.500 J-0.016 K0.000 F360.000 -G1 X102.042 Y173.500 Z-1.500 F360.000 -G1 X101.842 Y173.500 Z-1.300 F360.000 -G1 X87.158 Y173.500 Z-1.300 F360.000 -G1 X86.958 Y173.500 Z-1.500 F360.000 -G1 X23.000 Y173.500 Z-1.500 F360.000 -G3 X22.500 Y173.016 Z-1.500 I-0.000 J-0.500 K0.000 F360.000 -G2 X4.984 Y155.500 Z-1.500 I-17.502 J-0.015 K0.000 F360.000 -G3 X4.500 Y155.000 Z-1.500 I0.016 J-0.500 K0.000 F360.000 -G1 X4.500 Y115.042 Z-1.500 F360.000 -G1 X4.500 Y114.842 Z-1.300 F360.000 -G1 X4.500 Y100.158 Z-1.300 F360.000 -G1 X4.500 Y99.958 Z-1.500 F360.000 -G1 X4.500 Y60.000 Z-1.500 F360.000 -G3 X5.000 Y59.500 Z-1.500 I0.500 J-0.000 K0.000 F360.000 -G1 X16.990 Y59.500 Z-1.500 F360.000 -G2 X28.500 Y47.990 Z-1.500 I0.009 J-11.501 K0.000 F360.000 -G1 X28.500 Y5.000 Z-1.500 F360.000 -G3 X29.000 Y4.500 Z-1.500 I0.500 J-0.000 K0.000 F360.000 -G1 X91.458 Y4.500 Z-1.500 F360.000 -G1 X91.658 Y4.500 Z-1.300 F360.000 -G1 X106.342 Y4.500 Z-1.300 F360.000 -G1 X106.542 Y4.500 Z-1.500 F360.000 -G1 X169.000 Y4.500 Z-1.500 F360.000 -G3 X169.500 Y5.000 Z-1.500 I0.000 J0.500 K0.000 F360.000 -G1 X169.500 Y47.990 Z-1.500 F360.000 -G2 X181.010 Y59.500 Z-1.500 I11.501 J0.009 K0.000 F360.000 -G1 X193.000 Y59.500 Z-1.500 F360.000 -G3 X193.500 Y60.000 Z-1.500 I0.000 J0.500 K0.000 F360.000 -G1 X193.500 Y99.958 Z-1.500 F360.000 -G1 X193.500 Y100.158 Z-1.300 F360.000 -G1 X193.500 Y114.842 Z-1.300 F360.000 -G1 X193.500 Y115.042 Z-1.500 F360.000 -G1 X193.500 Y155.000 Z-1.500 F360.000 -G3 X193.014 Y155.500 Z-1.500 I-0.500 J0.000 K0.000 F360.000 -G1 X193.014 Y155.500 Z-2.100 F360.000 -G3 X193.000 Y155.500 Z-2.100 I-0.014 J-0.500 K0.000 F360.000 -G1 X184.008 Y155.500 Z-2.100 F360.000 -G2 X166.500 Y173.016 Z-2.100 I-0.007 J17.501 K0.000 F360.000 -G3 X166.000 Y173.500 Z-2.100 I-0.500 J-0.016 K0.000 F360.000 -G1 X102.642 Y173.500 Z-2.100 F360.000 -G1 X101.842 Y173.500 Z-1.300 F360.000 -G1 X87.158 Y173.500 Z-1.300 F360.000 -G1 X86.358 Y173.500 Z-2.100 F360.000 -G1 X23.000 Y173.500 Z-2.100 F360.000 -G3 X22.500 Y173.016 Z-2.100 I-0.000 J-0.500 K0.000 F360.000 -G2 X4.984 Y155.500 Z-2.100 I-17.502 J-0.015 K0.000 F360.000 -G3 X4.500 Y155.000 Z-2.100 I0.016 J-0.500 K0.000 F360.000 -G1 X4.500 Y115.642 Z-2.100 F360.000 -G1 X4.500 Y114.842 Z-1.300 F360.000 -G1 X4.500 Y100.158 Z-1.300 F360.000 -G1 X4.500 Y99.358 Z-2.100 F360.000 -G1 X4.500 Y60.000 Z-2.100 F360.000 -G3 X5.000 Y59.500 Z-2.100 I0.500 J-0.000 K0.000 F360.000 -G1 X16.990 Y59.500 Z-2.100 F360.000 -G2 X28.500 Y47.990 Z-2.100 I0.009 J-11.501 K0.000 F360.000 -G1 X28.500 Y5.000 Z-2.100 F360.000 -G3 X29.000 Y4.500 Z-2.100 I0.500 J-0.000 K0.000 F360.000 -G1 X90.858 Y4.500 Z-2.100 F360.000 -G1 X91.658 Y4.500 Z-1.300 F360.000 -G1 X106.342 Y4.500 Z-1.300 F360.000 -G1 X107.142 Y4.500 Z-2.100 F360.000 -G1 X169.000 Y4.500 Z-2.100 F360.000 -G3 X169.500 Y5.000 Z-2.100 I0.000 J0.500 K0.000 F360.000 -G1 X169.500 Y47.990 Z-2.100 F360.000 -G2 X181.010 Y59.500 Z-2.100 I11.501 J0.009 K0.000 F360.000 -G1 X193.000 Y59.500 Z-2.100 F360.000 -G3 X193.500 Y60.000 Z-2.100 I0.000 J0.500 K0.000 F360.000 -G1 X193.500 Y99.358 Z-2.100 F360.000 -G1 X193.500 Y100.158 Z-1.300 F360.000 -G1 X193.500 Y114.842 Z-1.300 F360.000 -G1 X193.500 Y115.642 Z-2.100 F360.000 -G1 X193.500 Y155.000 Z-2.100 F360.000 -G3 X193.014 Y155.500 Z-2.100 I-0.500 J0.000 K0.000 F360.000 +G0 Z7.000 +G0 X193.014 Y155.500 Z7.000 G0 X193.014 Y155.500 Z5.000 +G1 X193.014 Y155.500 Z0.500 F360.000 +G3 X193.000 Y155.500 Z0.500 I-0.014 J-0.500 K0.000 F360.000 +G1 X184.008 Y155.500 Z0.500 F360.000 +G2 X166.500 Y173.016 Z0.500 I-0.007 J17.501 K0.000 F360.000 +G3 X166.000 Y173.500 Z0.500 I-0.500 J-0.016 K0.000 F360.000 +G1 X102.140 Y173.500 Z0.500 F360.000 +G1 X101.640 Y173.500 Z1.000 F360.000 +G1 X87.360 Y173.500 Z1.000 F360.000 +G1 X86.860 Y173.500 Z0.500 F360.000 +G1 X23.000 Y173.500 Z0.500 F360.000 +G3 X22.500 Y173.016 Z0.500 I-0.000 J-0.500 K0.000 F360.000 +G2 X4.984 Y155.500 Z0.500 I-17.502 J-0.015 K0.000 F360.000 +G3 X4.500 Y155.000 Z0.500 I0.016 J-0.500 K0.000 F360.000 +G1 X4.500 Y115.140 Z0.500 F360.000 +G1 X4.500 Y114.640 Z1.000 F360.000 +G1 X4.500 Y100.360 Z1.000 F360.000 +G1 X4.500 Y99.860 Z0.500 F360.000 +G1 X4.500 Y60.000 Z0.500 F360.000 +G3 X5.000 Y59.500 Z0.500 I0.500 J-0.000 K0.000 F360.000 +G1 X16.990 Y59.500 Z0.500 F360.000 +G2 X28.500 Y47.990 Z0.500 I0.009 J-11.501 K0.000 F360.000 +G1 X28.500 Y5.000 Z0.500 F360.000 +G3 X29.000 Y4.500 Z0.500 I0.500 J-0.000 K0.000 F360.000 +G1 X91.360 Y4.500 Z0.500 F360.000 +G1 X91.860 Y4.500 Z1.000 F360.000 +G1 X106.140 Y4.500 Z1.000 F360.000 +G1 X106.640 Y4.500 Z0.500 F360.000 +G1 X169.000 Y4.500 Z0.500 F360.000 +G3 X169.500 Y5.000 Z0.500 I0.000 J0.500 K0.000 F360.000 +G1 X169.500 Y47.990 Z0.500 F360.000 +G2 X181.010 Y59.500 Z0.500 I11.501 J0.009 K0.000 F360.000 +G1 X193.000 Y59.500 Z0.500 F360.000 +G3 X193.500 Y60.000 Z0.500 I0.000 J0.500 K0.000 F360.000 +G1 X193.500 Y99.860 Z0.500 F360.000 +G1 X193.500 Y100.360 Z1.000 F360.000 +G1 X193.500 Y114.640 Z1.000 F360.000 +G1 X193.500 Y115.140 Z0.500 F360.000 +G1 X193.500 Y155.000 Z0.500 F360.000 +G3 X193.014 Y155.500 Z0.500 I-0.500 J0.000 K0.000 F360.000 +G1 X193.014 Y155.500 Z0.000 F360.000 +G3 X193.000 Y155.500 Z0.000 I-0.014 J-0.500 K0.000 F360.000 +G1 X184.008 Y155.500 Z0.000 F360.000 +G2 X166.500 Y173.016 Z0.000 I-0.007 J17.501 K0.000 F360.000 +G3 X166.000 Y173.500 Z0.000 I-0.500 J-0.016 K0.000 F360.000 +G1 X102.640 Y173.500 Z0.000 F360.000 +G1 X101.640 Y173.500 Z1.000 F360.000 +G1 X87.360 Y173.500 Z1.000 F360.000 +G1 X86.360 Y173.500 Z0.000 F360.000 +G1 X23.000 Y173.500 Z0.000 F360.000 +G3 X22.500 Y173.016 Z0.000 I-0.000 J-0.500 K0.000 F360.000 +G2 X4.984 Y155.500 Z0.000 I-17.502 J-0.015 K0.000 F360.000 +G3 X4.500 Y155.000 Z0.000 I0.016 J-0.500 K0.000 F360.000 +G1 X4.500 Y115.640 Z0.000 F360.000 +G1 X4.500 Y114.640 Z1.000 F360.000 +G1 X4.500 Y100.360 Z1.000 F360.000 +G1 X4.500 Y99.360 Z0.000 F360.000 +G1 X4.500 Y60.000 Z0.000 F360.000 +G3 X5.000 Y59.500 Z0.000 I0.500 J-0.000 K0.000 F360.000 +G1 X16.990 Y59.500 Z0.000 F360.000 +G2 X28.500 Y47.990 Z0.000 I0.009 J-11.501 K0.000 F360.000 +G1 X28.500 Y5.000 Z0.000 F360.000 +G3 X29.000 Y4.500 Z0.000 I0.500 J-0.000 K0.000 F360.000 +G1 X90.860 Y4.500 Z0.000 F360.000 +G1 X91.860 Y4.500 Z1.000 F360.000 +G1 X106.140 Y4.500 Z1.000 F360.000 +G1 X107.140 Y4.500 Z0.000 F360.000 +G1 X169.000 Y4.500 Z0.000 F360.000 +G3 X169.500 Y5.000 Z0.000 I0.000 J0.500 K0.000 F360.000 +G1 X169.500 Y47.990 Z0.000 F360.000 +G2 X181.010 Y59.500 Z0.000 I11.501 J0.009 K0.000 F360.000 +G1 X193.000 Y59.500 Z0.000 F360.000 +G3 X193.500 Y60.000 Z0.000 I0.000 J0.500 K0.000 F360.000 +G1 X193.500 Y99.360 Z0.000 F360.000 +G1 X193.500 Y100.360 Z1.000 F360.000 +G1 X193.500 Y114.640 Z1.000 F360.000 +G1 X193.500 Y115.640 Z0.000 F360.000 +G1 X193.500 Y155.000 Z0.000 F360.000 +G3 X193.014 Y155.500 Z0.000 I-0.500 J0.000 K0.000 F360.000 +G0 X193.014 Y155.500 Z7.000 (Finish operation: DressupTag) (Begin postamble) M5 diff --git a/drawing/plane.old b/drawing/plane.old deleted file mode 100644 index 37fc3eb1..00000000 --- a/drawing/plane.old +++ /dev/null @@ -1,355 +0,0 @@ -(Exported by FreeCAD) -(Post Processor: grbl_post) -(Output Time:2021-04-09 16:25:10.319632) -(Begin preamble) -G17 G90 -G21 -(Begin operation: Fixture) -(Path: Fixture) -G54 -(Finish operation: Fixture) -(Begin operation: Default Tool) -(Path: Default Tool) -(Default Tool) -(Begin toolchange) -( M6 T1.0 ) -M3 S10000.0 -(Finish operation: Default Tool) -(Begin operation: Profile001) -(Path: Profile001) -(Profile001) -(Compensated Tool Path. Diameter: 2.0) -G0 Z5.000 -G0 X28.912 Y69.912 -G0 Z3.000 -G1 X28.912 Y69.912 Z-0.200 F360.000 -G2 X28.117 Y66.601 Z-0.200 I-1.412 J-1.412 K0.000 F360.000 -G2 X26.883 Y70.399 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G2 X28.912 Y69.912 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X28.912 Y69.912 -G0 X27.529 Y163.503 -G0 X27.529 Y163.503 Z3.000 -G1 X27.529 Y163.503 Z-0.200 F360.000 -G2 X26.883 Y167.399 Z-0.200 I-0.029 J1.997 K0.000 F360.000 -G2 X28.117 Y163.601 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G2 X27.529 Y163.503 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X27.529 Y163.503 -G0 X141.505 Y158.095 -G0 X141.505 Y158.095 Z3.000 -G1 X141.505 Y158.095 Z-0.200 F360.000 -G2 X142.883 Y159.899 Z-0.200 I1.995 J-0.095 K0.000 F360.000 -G2 X144.117 Y156.101 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G2 X141.505 Y158.095 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -G0 X141.505 Y158.095 -G0 X143.459 Y62.996 -G0 X143.459 Y62.996 Z3.000 -G1 X143.459 Y62.996 Z-0.200 F360.000 -G2 X144.117 Y59.101 Z-0.200 I0.041 J-1.996 K0.000 F360.000 -G2 X141.601 Y60.383 Z-0.200 I-0.617 J1.899 K0.000 F360.000 -G2 X142.883 Y62.899 Z-0.200 I1.899 J0.617 K0.000 F360.000 -G2 X143.459 Y62.996 Z-0.200 I0.617 J-1.899 K0.000 F360.000 -G0 Z5.000 -G0 Z5.000 -(Finish operation: Profile001) -(Begin operation: Helix) -(Path: Helix) -(Helix) -(helix cut operation) -G0 Z5.000 -G0 X51.110 Y30.890 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X50.110 Y30.890 Z-0.750 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-1.500 I0.500 J0.000 F360.000 -G2 X50.110 Y30.890 Z-2.250 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-3.000 I0.500 J0.000 F360.000 -G2 X50.110 Y30.890 Z-3.000 I-0.500 J0.000 F360.000 -G2 X51.110 Y30.890 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X60.000 Y15.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X59.000 Y15.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X59.000 Y15.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X59.000 Y15.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X60.000 Y15.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X75.259 Y15.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X74.259 Y15.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X75.259 Y15.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X74.259 Y15.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X75.259 Y15.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X74.259 Y15.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X75.259 Y15.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X75.259 Y73.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X74.259 Y73.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X75.259 Y73.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X74.259 Y73.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X75.259 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X74.259 Y73.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X75.259 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X60.000 Y73.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X59.000 Y73.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X59.000 Y73.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X59.000 Y73.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X60.000 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X51.110 Y73.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X50.110 Y73.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X50.110 Y73.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X50.110 Y73.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X51.110 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X28.000 Y68.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X27.000 Y68.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X27.000 Y68.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X27.000 Y68.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X28.000 Y68.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X11.000 Y73.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X10.000 Y73.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X10.000 Y73.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X10.000 Y73.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X11.000 Y73.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X28.000 Y105.966 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X27.000 Y105.966 Z-0.750 I-0.500 J0.000 F360.000 -G2 X28.000 Y105.966 Z-1.500 I0.500 J0.000 F360.000 -G2 X27.000 Y105.966 Z-2.250 I-0.500 J0.000 F360.000 -G2 X28.000 Y105.966 Z-3.000 I0.500 J0.000 F360.000 -G2 X27.000 Y105.966 Z-3.000 I-0.500 J0.000 F360.000 -G2 X28.000 Y105.966 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X28.000 Y143.868 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X27.000 Y143.868 Z-0.750 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-1.500 I0.500 J0.000 F360.000 -G2 X27.000 Y143.868 Z-2.250 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-3.000 I0.500 J0.000 F360.000 -G2 X27.000 Y143.868 Z-3.000 I-0.500 J0.000 F360.000 -G2 X28.000 Y143.868 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X28.000 Y165.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X27.000 Y165.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X27.000 Y165.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X27.000 Y165.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X28.000 Y165.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X83.000 Y166.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X82.000 Y166.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X82.000 Y166.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X82.000 Y166.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X83.000 Y166.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X83.000 Y121.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X82.000 Y121.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X82.000 Y121.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X82.000 Y121.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X83.000 Y121.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X75.259 Y105.966 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X74.259 Y105.966 Z-0.750 I-0.500 J0.000 F360.000 -G2 X75.259 Y105.966 Z-1.500 I0.500 J0.000 F360.000 -G2 X74.259 Y105.966 Z-2.250 I-0.500 J0.000 F360.000 -G2 X75.259 Y105.966 Z-3.000 I0.500 J0.000 F360.000 -G2 X74.259 Y105.966 Z-3.000 I-0.500 J0.000 F360.000 -G2 X75.259 Y105.966 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X128.000 Y121.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X127.000 Y121.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X127.000 Y121.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X127.000 Y121.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X128.000 Y121.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X144.000 Y158.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X143.000 Y158.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X143.000 Y158.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X143.000 Y158.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X144.000 Y158.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X128.000 Y166.500 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X127.000 Y166.500 Z-0.750 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-1.500 I0.500 J0.000 F360.000 -G2 X127.000 Y166.500 Z-2.250 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-3.000 I0.500 J0.000 F360.000 -G2 X127.000 Y166.500 Z-3.000 I-0.500 J0.000 F360.000 -G2 X128.000 Y166.500 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X115.500 Y68.100 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X114.500 Y68.100 Z-0.750 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-1.500 I0.500 J0.000 F360.000 -G2 X114.500 Y68.100 Z-2.250 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-3.000 I0.500 J0.000 F360.000 -G2 X114.500 Y68.100 Z-3.000 I-0.500 J0.000 F360.000 -G2 X115.500 Y68.100 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X144.000 Y61.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X143.000 Y61.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X143.000 Y61.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X143.000 Y61.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X144.000 Y61.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 X187.500 Y79.000 -G0 Z3.000 -G1 Z0.000 F360.000 -G2 X186.500 Y79.000 Z-0.750 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-1.500 I0.500 J0.000 F360.000 -G2 X186.500 Y79.000 Z-2.250 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-3.000 I0.500 J0.000 F360.000 -G2 X186.500 Y79.000 Z-3.000 I-0.500 J0.000 F360.000 -G2 X187.500 Y79.000 Z-3.000 I0.500 J0.000 F360.000 -G0 Z3.000 -G0 Z5.000 -(Finish operation: Helix) -(Begin operation: DressupTag) -(Path: DressupTag) -G0 Z5.000 -G0 X193.014 Y155.500 Z5.000 -G0 X193.014 Y155.500 Z3.000 -G1 X193.014 Y155.500 Z-1.500 F360.000 -G2 X193.500 Y155.000 Z-1.500 I-0.014 J-0.500 K0.000 F360.000 -G1 X193.500 Y114.942 Z-1.500 F360.000 -G1 X193.500 Y114.842 Z-1.400 F360.000 -G1 X193.500 Y100.158 Z-1.400 F360.000 -G1 X193.500 Y100.058 Z-1.500 F360.000 -G1 X193.500 Y60.000 Z-1.500 F360.000 -G2 X193.000 Y59.500 Z-1.500 I-0.500 J-0.000 K0.000 F360.000 -G1 X181.010 Y59.500 Z-1.500 F360.000 -G3 X169.500 Y47.990 Z-1.500 I-0.009 J-11.501 K0.000 F360.000 -G1 X169.500 Y5.000 Z-1.500 F360.000 -G2 X169.000 Y4.500 Z-1.500 I-0.500 J-0.000 K0.000 F360.000 -G1 X106.442 Y4.500 Z-1.500 F360.000 -G1 X106.342 Y4.500 Z-1.400 F360.000 -G1 X91.658 Y4.500 Z-1.400 F360.000 -G1 X91.558 Y4.500 Z-1.500 F360.000 -G1 X29.000 Y4.500 Z-1.500 F360.000 -G2 X28.500 Y5.000 Z-1.500 I-0.000 J0.500 K0.000 F360.000 -G1 X28.500 Y47.990 Z-1.500 F360.000 -G3 X16.990 Y59.500 Z-1.500 I-11.501 J0.009 K0.000 F360.000 -G1 X5.000 Y59.500 Z-1.500 F360.000 -G2 X4.500 Y60.000 Z-1.500 I-0.000 J0.500 K0.000 F360.000 -G1 X4.500 Y100.058 Z-1.500 F360.000 -G1 X4.500 Y100.158 Z-1.400 F360.000 -G1 X4.500 Y114.842 Z-1.400 F360.000 -G1 X4.500 Y114.942 Z-1.500 F360.000 -G1 X4.500 Y155.000 Z-1.500 F360.000 -G2 X4.984 Y155.500 Z-1.500 I0.500 J-0.000 K0.000 F360.000 -G3 X22.500 Y173.016 Z-1.500 I0.015 J17.502 K0.000 F360.000 -G2 X23.000 Y173.500 Z-1.500 I0.500 J-0.016 K0.000 F360.000 -G1 X87.058 Y173.500 Z-1.500 F360.000 -G1 X87.158 Y173.500 Z-1.400 F360.000 -G1 X101.842 Y173.500 Z-1.400 F360.000 -G1 X101.942 Y173.500 Z-1.500 F360.000 -G1 X166.000 Y173.500 Z-1.500 F360.000 -G2 X166.500 Y173.016 Z-1.500 I-0.000 J-0.500 K0.000 F360.000 -G3 X184.008 Y155.500 Z-1.500 I17.501 J-0.015 K0.000 F360.000 -G1 X193.000 Y155.500 Z-1.500 F360.000 -G2 X193.014 Y155.500 Z-1.500 I0.000 J-0.500 K0.000 F360.000 -G1 X193.014 Y155.500 Z-2.200 F360.000 -G2 X193.500 Y155.000 Z-2.200 I-0.014 J-0.500 K0.000 F360.000 -G1 X193.500 Y115.642 Z-2.200 F360.000 -G1 X193.500 Y114.842 Z-1.400 F360.000 -G1 X193.500 Y100.158 Z-1.400 F360.000 -G1 X193.500 Y99.358 Z-2.200 F360.000 -G1 X193.500 Y60.000 Z-2.200 F360.000 -G2 X193.000 Y59.500 Z-2.200 I-0.500 J-0.000 K0.000 F360.000 -G1 X181.010 Y59.500 Z-2.200 F360.000 -G3 X169.500 Y47.990 Z-2.200 I-0.009 J-11.501 K0.000 F360.000 -G1 X169.500 Y5.000 Z-2.200 F360.000 -G2 X169.000 Y4.500 Z-2.200 I-0.500 J-0.000 K0.000 F360.000 -G1 X107.142 Y4.500 Z-2.200 F360.000 -G1 X106.342 Y4.500 Z-1.400 F360.000 -G1 X91.658 Y4.500 Z-1.400 F360.000 -G1 X90.858 Y4.500 Z-2.200 F360.000 -G1 X29.000 Y4.500 Z-2.200 F360.000 -G2 X28.500 Y5.000 Z-2.200 I-0.000 J0.500 K0.000 F360.000 -G1 X28.500 Y47.990 Z-2.200 F360.000 -G3 X16.990 Y59.500 Z-2.200 I-11.501 J0.009 K0.000 F360.000 -G1 X5.000 Y59.500 Z-2.200 F360.000 -G2 X4.500 Y60.000 Z-2.200 I-0.000 J0.500 K0.000 F360.000 -G1 X4.500 Y99.358 Z-2.200 F360.000 -G1 X4.500 Y100.158 Z-1.400 F360.000 -G1 X4.500 Y114.842 Z-1.400 F360.000 -G1 X4.500 Y115.642 Z-2.200 F360.000 -G1 X4.500 Y155.000 Z-2.200 F360.000 -G2 X4.984 Y155.500 Z-2.200 I0.500 J-0.000 K0.000 F360.000 -G3 X22.500 Y173.016 Z-2.200 I0.015 J17.502 K0.000 F360.000 -G2 X23.000 Y173.500 Z-2.200 I0.500 J-0.016 K0.000 F360.000 -G1 X86.358 Y173.500 Z-2.200 F360.000 -G1 X87.158 Y173.500 Z-1.400 F360.000 -G1 X101.842 Y173.500 Z-1.400 F360.000 -G1 X102.642 Y173.500 Z-2.200 F360.000 -G1 X166.000 Y173.500 Z-2.200 F360.000 -G2 X166.500 Y173.016 Z-2.200 I-0.000 J-0.500 K0.000 F360.000 -G3 X184.008 Y155.500 Z-2.200 I17.501 J-0.015 K0.000 F360.000 -G1 X193.000 Y155.500 Z-2.200 F360.000 -G2 X193.014 Y155.500 Z-2.200 I0.000 J-0.500 K0.000 F360.000 -G0 X193.014 Y155.500 Z5.000 -(Finish operation: DressupTag) -(Begin postamble) -M5 -G17 G90 -M2 diff --git a/images/internal.png b/images/internal.png index 13bf6825..231ce75e 100644 Binary files a/images/internal.png and b/images/internal.png differ diff --git a/images/internal_synoptic.odp b/images/internal_synoptic.odp index d7dbf568..4df525e4 100644 Binary files a/images/internal_synoptic.odp and b/images/internal_synoptic.odp differ diff --git a/receiver_cfg/Septentrio_Mosaic-X5.cfg b/receiver_cfg/Septentrio_Mosaic-X5.cfg new file mode 100644 index 00000000..e7bd148a --- /dev/null +++ b/receiver_cfg/Septentrio_Mosaic-X5.cfg @@ -0,0 +1,17 @@ +# Config file for using a Septentrio Mosaic X5 with RTKBase +setSBFOutput, Stream1, USB1 +setSBFOutput, Stream1, , , sec1 +setSBFOutput, Stream1, , MeasEpoch+MeasExtra+EndOfMeas +setSBFOutput, Stream1, , +GPSRawCA+GPSRawL2C+GPSRawL5 +setSBFOutput, Stream1, , +GLORawCA +setSBFOutput, Stream1, , +GALRawFNAV+GALRawINAV+GALRawCNAV +setSBFOutput, Stream1, , +BDSRaw+BDSRawB1C+BDSRawB2a+BDSRawB2b +setSBFOutput, Stream1, , +QZSRawL1CA+QZSRawL2C+QZSRawL5 +setSBFOutput, Stream1, , +NAVICRaw +setSBFOutput, Stream1, , +GEORawL1+GEORawL5 +setSignalTracking, GPSL1CA+GPSL1PY+GPSL2PY+GPSL2C+GPSL5+GLOL1CA+GLOL2P+GLOL2CA+GLOL3+GALL1BC+GALE6BC+GALE5a+GALE5b+GALE5+GEOL1+GEOL5+BDSB1I+BDSB2I+BDSB3I+BDSB1C+BDSB2a+BDSB2b+QZSL1CA+QZSL2C+QZSL5+QZSL1CB+NAVICL5 +setSBFOutput, Stream1, , +PVTGeodetic+ChannelStatus+ReceiverStatus+SatVisibility+ReceiverTime +setPVTMode, Static +setPPSParameters, sec1, Low2High, , UTC +setUSBInternetAccess, on +#END \ No newline at end of file diff --git a/rtkbase_update.sh b/rtkbase_update.sh index b46708b4..f8a394b3 100755 --- a/rtkbase_update.sh +++ b/rtkbase_update.sh @@ -15,6 +15,14 @@ old_version=$4 standard_user=$5 checking=$6 +#argument checking +[[ -d "${source_directory}" ]] || { echo 'ERROR! source_directory is not a directory'; exit 1; } +[[ -d "${destination_directory}" ]] || { echo 'ERROR! destination_directory is not a directory'; exit 1; } +#[[ -d "${data_dir}" ]] || { echo 'ERROR! data_dir is not a directory'; exit 1; } <- not a full path directory, just the directory name +#[[ "${old_version}" =~ ^[+-]?[0-9]+\.?[0-9]*$ ]] || { echo 'ERROR! wrong type for current_version variable'; exit 1; } <- doesn't work for 2.5.0 or 2.4b +[[ $(id -u "${standard_user}") ]] &>/dev/null || { echo 'ERROR! user does not exist'; exit 1; } +# $checking variable doesn't need to be checked as it is used only if it is set to '--checking' + #store service status before upgrade str2str_active=$(systemctl is-active str2str_tcp) str2str_ntrip_A_active=$(systemctl is-active str2str_ntrip_A) @@ -23,9 +31,14 @@ str2str_local_caster=$(systemctl is-active str2str_local_ntrip_caster) str2str_rtcm=$(systemctl is-active str2str_rtcm_svr) str2str_serial=$(systemctl is-active str2str_rtcm_serial) str2str_file=$(systemctl is-active str2str_file) +rtkrcv_raw2nmea=$(systemctl is-active rtkbase_raw2nmea) check_before_update() { - TOO_OLD='You'"'"'re Operating System is too old\nPlease update it or reflash you SDCard with a more recent RTKBase image\n' + TOO_OLD='Your Operating System is too old!\n + Please reflash your SDCard with a more recent RTKBase image, or upgrade your OS.\n + Don'"'"'t forget to backup your settings.\n\n + RTKBase repository\n\n + Documentation CentipedeRTK' if [[ -f /etc/os-release ]] then @@ -36,21 +49,21 @@ check_before_update() { case $ID in debian) - if (( $(echo "$VERSION_ID < 10" | bc -l) )) + if (( $(echo "$VERSION_ID < 11" | bc -l) )) then printf "${TOO_OLD}" >/dev/stderr exit 1 fi ;; raspbian) - if (( $(echo "$VERSION_ID < 10" | bc -l) )) + if (( $(echo "$VERSION_ID < 11" | bc -l) )) then printf "${TOO_OLD}" >/dev/stderr exit 1 fi ;; ubuntu) - if (( $(echo "$VERSION_ID < 20.04" | bc -l) )) + if (( $(echo "$VERSION_ID < 22.04" | bc -l) )) then printf "${TOO_OLD}" >/dev/stderr exit 1 @@ -65,7 +78,7 @@ rm -rf /var/tmp/rtkbase.old mkdir /var/tmp/rtkbase.old echo "copy rtkbase to rtkbase.old except /data directory" -cp -r ${destination_directory}/!(${data_dir}) /var/tmp/rtkbase.old +cp -r ${destination_directory}/!(${data_dir}|venv) /var/tmp/rtkbase.old #Don't do that or it will stop the update process #systemctl stop rtkbase_web.service @@ -92,15 +105,15 @@ insert_rtcm_msg() { local delay=${4} new_rtcm='' - if [[ ! $(echo ${text_line} | grep ${msg_to_insert}) ]] + if [[ ! $(echo ${text_line} | grep -q ${msg_to_insert}) ]] then for (( i=${msg_to_insert}; i<=${highest_msg}; i++ )) do - if [[ $(echo ${text_line} | grep $i) ]] + if [[ $(echo ${text_line} | grep -q $i) ]] then echo 'insert '${msg_to_insert}' before '$i new_rtcm=$(echo ${text_line} | sed 's|'"${i}"'|'"${msg_to_insert}${delay}"',&|') - #echo ${new_rtcm} + echo ${new_rtcm} break fi done @@ -110,186 +123,14 @@ insert_rtcm_msg() { fi } -upd_2.0.2() { - if [[ $(grep -E "^receiver_format='ubx'" ${destination_directory}/settings.conf) ]] - then - # Add -TAJD=1 option to rtcm/ntrip output for ublox receivers - grep -q "^ntrip_receiver_options" ${destination_directory}/settings.conf || \ - sed -i "/^rtcm_msg=.*/a ntrip_receiver_options='-TADJ=1'" ${destination_directory}/settings.conf - grep -q "^rtcm_receiver_options" ${destination_directory}/settings.conf || \ - sed -i "/^rtcm_svr_msg=.*/a rtcm_receiver_options='-TADJ=1'" ${destination_directory}/settings.conf - fi - #upd_2.0.4 -} - -upd_2.1.0() { - upd_2.1.1 "$@" -} - -upd_2.1.1() { - #stopping services to copy new rtklib app - #systemctl stop rtkbase_web <- don't do that, it will kill this script process. - systemctl stop str2str_tcp - #Get Rtklib 2.4.3 b34 release - wget -qO - https://github.com/tomojitakasu/RTKLIB/archive/v2.4.3-b34.tar.gz | tar -xvz - #Install Rtklib app - make --directory=RTKLIB-2.4.3-b34/app/consapp/str2str/gcc - make --directory=RTKLIB-2.4.3-b34/app/consapp/str2str/gcc install - make --directory=RTKLIB-2.4.3-b34/app/consapp/rtkrcv/gcc - make --directory=RTKLIB-2.4.3-b34/app/consapp/rtkrcv/gcc install - make --directory=RTKLIB-2.4.3-b34/app/consapp/convbin/gcc - make --directory=RTKLIB-2.4.3-b34/app/consapp/convbin/gcc install - #deleting RTKLIB - rm -rf RTKLIB-2.4.3-b34/ - - #restarting str2str_tcp service - systemctl start str2str_tcp - - #update python module - python3 -m pip install -r ${destination_directory}'/web_app/requirements.txt' - - #copying new service - file_path=${destination_directory}'/unit/str2str_rtcm_serial.service' - file_name=$(basename ${file_path}) - echo copying ${file_name} - sed -e 's|{script_path}|'"$(readlink -f "$2")"'|' -e 's|{user}|'"${standard_user}"'|' ${file_path} > /etc/systemd/system/${file_name} - systemctl daemon-reload - - #inserting new rtcm message 1008 and 1033 inside rtcm_msg and rtcm_svr_msg - insert_rtcm_msg $(grep "^rtcm_msg=" ${destination_directory}/settings.conf) 1008 1042 '(10)' && \ - sed -i '/^rtcm_msg=/c\'"${new_rtcm}" ${destination_directory}/settings.conf - insert_rtcm_msg $(grep "^rtcm_msg=" ${destination_directory}/settings.conf) 1033 1230 '(10)' && \ - sed -i '/^rtcm_msg=/c\'"${new_rtcm}" ${destination_directory}/settings.conf - insert_rtcm_msg $(grep "^rtcm_svr_msg=" ${destination_directory}/settings.conf) 1008 1042 '(10)' && \ - sed -i '/^rtcm_svr_msg=/c\'"${new_rtcm}" ${destination_directory}/settings.conf - insert_rtcm_msg $(grep "^rtcm_svr_msg=" ${destination_directory}/settings.conf) 1033 1230 '(10)' && \ - sed -i '/^rtcm_svr_msg=/c\'"${new_rtcm}" ${destination_directory}/settings.conf - - #restarting runnning rtcm services to send the new messages. - # my bad ! these services are already stopped. the command bellow won't restart them - #systemctl is-active --quiet str2str_ntrip && systemctl restart str2str_ntrip - #systemctl is-active --quiet str2str_rtcm_svr && systemctl restart str2str_rtcm_svr -} - -upd_2.2.0() { - #update python module - python3 -m pip install -r ${destination_directory}'/web_app/requirements.txt' --extra-index-url https://www.piwheels.org/simple - - #copying new service - file_path=${destination_directory}'/unit/str2str_local_ntrip_caster.service' - file_name=$(basename ${file_path}) - echo copying ${file_name} - sed -e 's|{script_path}|'"$(readlink -f "$2")"'|' -e 's|{user}|'"${standard_user}"'|' ${file_path} > /etc/systemd/system/${file_name} - - #fix previous wrong path to run_cast.sh inside str2str_rtcm_serial.service during 2.1.1 to 2.2.0 update (/var/tmp/rtkbase/run_cast.sh) - sed -i 's|'/var/tmp/rtkbase'|'"$(readlink -f "$2")"'|' /etc/systemd/system/str2str_rtcm_serial.service - - systemctl daemon-reload -} - -upd_2.3.0() { - upd_2.3.2 "$@" -} - -upd_2.3.1() { - upd_2.3.2 "$@" -} - -upd_2.3.2() { -#Add restart condition in gpsd.service - if ! grep -q '^Restart=' /etc/systemd/system/gpsd.service ; then - sed -i '/^ExecStart=.*/a Restart=always' /etc/systemd/system/gpsd.service - sed -i '/^Restart=always.*/a RestartSec=30' /etc/systemd/system/gpsd.service - fi - systemctl daemon-reload - upd_2.3.3 "$@" -} - -upd_2.3.3() { - #update gpsd unit file - cp /lib/systemd/system/gpsd.service /etc/systemd/system/gpsd.service - sed -i 's/^After=.*/After=str2str_tcp.service/' /etc/systemd/system/gpsd.service - sed -i '/^# Needed with chrony/d' /etc/systemd/system/gpsd.service - #Add restart condition - grep -qi '^Restart=' /etc/systemd/system/gpsd.service || sed -i '/^ExecStart=.*/a Restart=always' /etc/systemd/system/gpsd.service - grep -qi '^RestartSec=' /etc/systemd/system/gpsd.service || sed -i '/^Restart=always.*/a RestartSec=30' /etc/systemd/system/gpsd.service - #Add ExecStartPre condition to not start gpsd if str2str_tcp is not running. See https://github.com/systemd/systemd/issues/1312 - grep -qi '^ExecStartPre=' /etc/systemd/system/gpsd.service || sed -i '/^ExecStart=.*/i ExecStartPre=systemctl is-active str2str_tcp.service' /etc/systemd/system/gpsd.service - systemctl daemon-reload - systemctl restart gpsd - upd_2.3.4 "$@" -} - upgrade_rtklib() { systemctl stop str2str_tcp + systemctl stop rtkbase_raw2nmea bin_path=$(dirname "$(command -v str2str)") rm "${bin_path}"'/str2str' "${bin_path}"'/rtkrcv' "${bin_path}"'/convbin' "${destination_directory}"'/tools/install.sh' --user "${standard_user}" --rtklib } -upd_2.3.4() { - #store service status before stopping str2str - str2str_active=$(systemctl is-active str2str_tcp) - str2str_ntrip_active=$(systemctl is-active str2str_ntrip) - str2str_local_caster=$(systemctl is-active str2str_local_ntrip_caster) - str2str_rtcm=$(systemctl is-active str2str_rtcm_svr) - str2str_serial=$(systemctl is-active str2str_rtcm_serial) - str2str_file=$(systemctl is-active str2str_file) - systemctl stop str2str_tcp - #Add new requirements for v2.4 - ${destination_directory}'/tools/install.sh' --user "${standard_user}" --dependencies - # Copy new services - systemctl stop str2str_ntrip.service - systemctl disable str2str_ntrip.service - rm /etc/systemd/system/str2str_ntrip.service - systemctl reset-failed - file_path=${destination_directory}'/unit/str2str_ntrip_A.service' - file_name=$(basename ${file_path}) - echo copying ${file_name} - sed -e 's|{script_path}|'"$(readlink -f "$2")"'|' -e 's|{user}|'"${standard_user}"'|' ${file_path} > /etc/systemd/system/${file_name} - file_path=${destination_directory}'/unit/str2str_ntrip_B.service' - file_name=$(basename ${file_path}) - echo copying ${file_name} - sed -e 's|{script_path}|'"$(readlink -f "$2")"'|' -e 's|{user}|'"${standard_user}"'|' ${file_path} > /etc/systemd/system/${file_name} - systemctl daemon-reload -#update rtklib binary to the one from rtklibexplorer fork. - upgrade_rtklib -#update python module - "${destination_directory}"'/tools/install.sh' --user "${standard_user}" --rtkbase-requirements -# Get F9P firmware release - source <( grep '=' "${destination_directory}"/settings.conf ) - if [[ $(python3 "${destination_directory}"/tools/ubxtool -f /dev/"${com_port}" -s ${com_port_settings%%:*} -p MON-VER) =~ 'ZED-F9P' ]] - then - echo 'Get F9P firmware release' - firmware=$(python3 "${destination_directory}"/tools/ubxtool -f /dev/"${com_port}" -s ${com_port_settings%%:*} -p MON-VER | grep 'FWVER' | awk '{print $NF}') - grep -q "^receiver_firmware" ${destination_directory}/settings.conf || \ - sed -i "/^receiver_format=.*/a receiver_firmware=\'${firmware}\'" ${destination_directory}/settings.conf - fi -#restart str2str if it was active before upgrading rtklib - [ $str2str_active = 'active' ] && systemctl start str2str_tcp -#replace parameters from str2str_ntrip to str2str_ntrip_A service - sed -i 's/^\[ntrip\]/\[ntrip_A\]/' ${destination_directory}/settings.conf - sed -i 's/^svr_addr=/svr_addr_a=/' ${destination_directory}/settings.conf - sed -i 's/^svr_port=/svr_port_a=/' ${destination_directory}/settings.conf - sed -i 's/^svr_pwd=/svr_pwd_a=/' ${destination_directory}/settings.conf - sed -i 's/^mnt_name=/mnt_name_a=/' ${destination_directory}/settings.conf - sed -i 's/^rtcm_msg=/rtcm_msg_a=/' ${destination_directory}/settings.conf - sed -i 's/^ntrip_receiver_options=/ntrip_a_receiver_options=/' ${destination_directory}/settings.conf - -#start str2str_ntrip_A if str2str_ntrip was active before upgrading rtklib. - [ $str2str_ntrip_active = 'active' ] && systemctl enable str2str_ntrip_A && systemctl start str2str_ntrip_A -# restart previously running services - [ $str2str_local_caster = 'active' ] && systemctl start str2str_local_ntrip_caster - [ $str2str_rtcm = 'active' ] && systemctl start str2str_rtcm_svr - [ $str2str_serial = 'active' ] && systemctl start str2str_rtcm_serial - [ $str2str_file = 'active' ] && systemctl start str2str_file -} - -upd_2.4b() { - echo 'Calling upd2.3.4' - upd_2.3.4 "$@" -} - upd_2.4.0() { echo '####################' echo 'Update from 2.4.0' @@ -322,7 +163,7 @@ upd_2.4.2() { rm -r /var/log/sysstat/ fi # end of Orange Pi Zero section - ${destination_directory}/tools/install.sh --user "${standard_user}" --dependencies --rtkbase-requirements --unit-files + "${destination_directory}"/tools/install.sh --user "${standard_user}" --dependencies --rtkbase-requirements --unit-files #upgrade rtklib to b34h upgrade_rtklib #restart str2str if it was active before upgrading rtklib @@ -337,6 +178,32 @@ upd_2.4.2() { return 0 } +upd_2.5.0 () { + # only for Orange Pi Zero, update armbian-ramlog (https://github.com/Stefal/build/issues/16) + computer_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) + sbc_array=('Xunlong Orange Pi Zero') + if printf '%s\0' "${sbc_array[@]}" | grep -Fxqz -- "${computer_model}" && + lsb_release -c | grep -qE 'bullseye|bookworm' && + grep -qE 'armbian' /etc/os-release + then + echo 'Updating armbian-ramlog' + sed -i 's/armbian-ramlog)" | while/armbian-ramlog)|\\.journal" | while/' /usr/lib/armbian/armbian-ramlog + fi + # end of Orange Pi Zero section + "${destination_directory}"/tools/install.sh --user "${standard_user}" --dependencies --rtkbase-requirements --unit-files + "${destination_directory}"/venv/bin/python -m pip uninstall eventlet -y + #upgrade rtklib to b34j + upgrade_rtklib + #remove sbas rtcm message + sed -i -r '/^rtcm_/s/1107(\([0-9]+\))?,//' "${destination_directory}"/settings.conf + +} + +#this update function is here only for testing update, but could be useful in case of a failed 2.5 to 2.6 update. +upd_2.6.0() { + upd_2.5.0 +} + #check if we can apply the update #FOR THE OLDER ME -> Don't forget to modify the os detection if there is a 2.5.x release !!! [[ $checking == '--checking' ]] && check_before_update && exit @@ -361,8 +228,22 @@ sed -i '/^\[general\]/a updated=true' ${destination_directory}/settings.conf #change rtkbase's content owner chown -R ${standard_user}:${standard_user} ${destination_directory} + #restart str2str if it was active before upgrading rtklib + # restart not nedeed if RTKlib was not upgraded + [ $str2str_active = 'active' ] && systemctl restart str2str_tcp + [ $str2str_file = 'active' ] && systemctl restart str2str_file + [ $rtkrcv_raw2nmea = 'active' ] && systemctl restart rtkbase_raw2nmea + # restart previously running services + # restart needed with all update to propagate the release number in the rtcm stream + [ $str2str_ntrip_A_active = 'active' ] && systemctl restart str2str_ntrip_A + [ $str2str_ntrip_B_active = 'active' ] && systemctl restart str2str_ntrip_B + [ $str2str_local_caster = 'active' ] && systemctl restart str2str_local_ntrip_caster + [ $str2str_rtcm = 'active' ] && systemctl restart str2str_rtcm_svr + [ $str2str_serial = 'active' ] && systemctl restart str2str_rtcm_serial + + #if a reboot is needed #systemctl reboot - -echo "Restart web server" +echo 'RTKBase update ending...' +echo 'Restart web server' systemctl restart rtkbase_web.service diff --git a/run_cast.sh b/run_cast.sh index afdfe2c7..db7a656f 100755 --- a/run_cast.sh +++ b/run_cast.sh @@ -4,8 +4,8 @@ # You can read the RTKLIB manual for more str2str informations: # https://github.com/tomojitakasu/RTKLIB -BASEDIR=$(dirname "$0") -source <( grep '=' ${BASEDIR}/settings.conf ) #import settings +BASEDIR="$(dirname "$0")" +source <( grep -v '^#' "${BASEDIR}"/settings.conf | grep '=' ) #import settings receiver_info="RTKBase ${receiver},${version} ${receiver_firmware}" in_serial="serial://${com_port}:${com_port_settings}#${receiver_format}" @@ -40,6 +40,14 @@ out_rtcm_svr="tcpsvr://:${rtcm_svr_port}#rtcm3 -msg ${rtcm_svr_msg} -p ${positio #add receiver options if it exists [[ ! -z "${rtcm_receiver_options}" ]] && out_rtcm_svr=""${out_rtcm_svr}" -opt "${rtcm_receiver_options}"" +out_rtcm_client="tcpcli://${rtcm_client_user}:${rtcm_client_pwd}@${rtcm_client_addr}:${rtcm_client_port}#rtcm3 -msg ${rtcm_client_msg} -p ${position}" +#add receiver options if it exists +[[ ! -z "${rtcm_client_receiver_options}" ]] && out_rtcm_client=""${out_rtcm_client}" -opt "${rtcm_receiver_client_options}"" + +out_rtcm_udp_svr="udpsvr://:${rtcm_udp_svr_port}#rtcm3 -msg ${rtcm_udp_svr_msg} -p ${position}" +#add receiver options if it exists +[[ ! -z "${rtcm_udp_svr_receiver_options}" ]] && out_rtcm_udp_svr=""${out_rtcm_udp_svr}" -opt "${rtcm_udp_svr_receiver_options}"" + out_rtcm_serial="serial://${out_com_port}:${out_com_port_settings}#rtcm3 -msg ${rtcm_serial_msg} -p ${position}" #add receiver options if it exists [[ ! -z "${rtcm_serial_receiver_options}" ]] && out_rtcm_serial=""${out_rtcm_serial}" -opt "${rtcm_serial_receiver_options}"" @@ -71,7 +79,17 @@ mkdir -p ${logdir} #echo ${cast} -in ${!1} -out $out_rtcm_svr ${cast} -in ${!1} -out ${out_rtcm_svr} -i "${receiver_info}" -a "${antenna_info}" -t ${level} -fl ${logdir}/str2str_rtcm_svr.log & ;; - + + out_rtcm_client) + #echo ${cast} -in ${!1} -out $out_rtcm_client + ${cast} -in ${!1} -out ${out_rtcm_client} -i "${receiver_info}" -a "${antenna_info}" -t ${level} -fl ${logdir}/str2str_rtcm_client.log & + ;; + + out_rtcm_udp_svr) + #echo ${cast} -in ${!1} -out $out_rtcm_udp_svr + ${cast} -in ${!1} -out ${out_rtcm_udp_svr} -i "${receiver_info}" -a "${antenna_info}" -t ${level} -fl ${logdir}/str2str_rtcm_udp_svr.log & + ;; + out_rtcm_serial) #echo ${cast} -in ${!1} -out $out_rtcm_serial ${cast} -in ${!1} -out ${out_rtcm_serial} -i "${receiver_info}" -a "${antenna_info}" -t ${level} -fl ${logdir}/str2str_rtcm_serial.log & diff --git a/settings.conf.default b/settings.conf.default index cfe9f01c..7d10f867 100644 --- a/settings.conf.default +++ b/settings.conf.default @@ -2,9 +2,9 @@ [general] # Version -version=2.5.0 +version=2.6.0 # Rtkbase upgrade mandatory "checkpoint" -checkpoint_version=2.6.0 +checkpoint_version=2.7.0 # User who runs str2str_file service user= # NTRIP caster program @@ -50,6 +50,12 @@ tcp_port='5015' ext_tcp_source='' #ext_tcp_port is the port used for ext_tcp_source ext_tcp_port='' +#ip address of the integrated web service (ie on Mosaic X5) +gnss_rcv_web_ip=192.168.3.1 +#port number for the Flask proxy app used to display the Gnss receiver web service +gnss_rcv_web_proxy_port=9090 +#port number for the raw2nmea service +nmea_port='5014' [local_storage] @@ -129,6 +135,45 @@ rtcm_svr_msg='1004,1005(10),1006,1008(10),1012,1019,1020,1033(10),1042,1045,1046 #Receiver dependent options rtcm_receiver_options='' +[rtcm_client] + +# RTCM client options + +#port for rtcm client +rtcm_client_addr='' +rtcm_client_port='80' +#user/password credentials to connect to the server +rtcm_client_user='' +rtcm_client_pwd='' +#messages for rtcm client use +rtcm_client_msg='1004,1005(10),1006,1008(10),1012,1019,1020,1033(10),1042,1045,1046,1077,1087,1097,1107,1127,1230' +#Receiver dependent options +rtcm_client_receiver_options='' + +[rtcm_udp_svr] + +#RTCM UDP Server options + +#port for rtcm UDP use +rtcm_udp_svr_port='' +#messages for rtcm udp use +rtcm_udp_svr_msg='1004,1005(10),1006,1008(10),1012,1019,1020,1033(10),1042,1045,1046,1077,1087,1097,1107,1127,1230' +#Receiver dependent options +rtcm_udp_svr_receiver_options='' + +[rtcm_udp_client] + +#RTCM UDP Client options + +#address for rtcm UDP +rtcm_udp_client_addr='' +#port for rtcm UDP use +rtcm_udp_client_port='' +#messages for rtcm udp use +rtcm_udp_client_msg='1004,1005(10),1006,1008(10),1012,1019,1020,1033(10),1042,1045,1046,1077,1087,1097,1107,1127,1230' +#Receiver dependent options +rtcm_udp_client_receiver_options='' + [rtcm_serial] # Serial output RTCM options diff --git a/tools/bin/rtklib_b34i/armv6l/convbin b/tools/bin/rtklib_b34i/armv6l/convbin deleted file mode 100755 index 5598098a..00000000 Binary files a/tools/bin/rtklib_b34i/armv6l/convbin and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv6l/rtkrcv b/tools/bin/rtklib_b34i/armv6l/rtkrcv deleted file mode 100755 index 197bf415..00000000 Binary files a/tools/bin/rtklib_b34i/armv6l/rtkrcv and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv6l/str2str b/tools/bin/rtklib_b34i/armv6l/str2str deleted file mode 100755 index 899a4199..00000000 Binary files a/tools/bin/rtklib_b34i/armv6l/str2str and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv7l/convbin b/tools/bin/rtklib_b34i/armv7l/convbin deleted file mode 100755 index 5598098a..00000000 Binary files a/tools/bin/rtklib_b34i/armv7l/convbin and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv7l/rtkrcv b/tools/bin/rtklib_b34i/armv7l/rtkrcv deleted file mode 100755 index 197bf415..00000000 Binary files a/tools/bin/rtklib_b34i/armv7l/rtkrcv and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv7l/str2str b/tools/bin/rtklib_b34i/armv7l/str2str deleted file mode 100755 index 899a4199..00000000 Binary files a/tools/bin/rtklib_b34i/armv7l/str2str and /dev/null differ diff --git a/tools/bin/rtklib_b34i/armv6l/compiled_with_buster b/tools/bin/rtklib_b34j/aarch64/compiled_with_bookworm similarity index 100% rename from tools/bin/rtklib_b34i/armv6l/compiled_with_buster rename to tools/bin/rtklib_b34j/aarch64/compiled_with_bookworm diff --git a/tools/bin/rtklib_b34j/aarch64/convbin b/tools/bin/rtklib_b34j/aarch64/convbin new file mode 100755 index 00000000..23b7f878 Binary files /dev/null and b/tools/bin/rtklib_b34j/aarch64/convbin differ diff --git a/tools/bin/rtklib_b34j/aarch64/rtkrcv b/tools/bin/rtklib_b34j/aarch64/rtkrcv new file mode 100755 index 00000000..c66a69b2 Binary files /dev/null and b/tools/bin/rtklib_b34j/aarch64/rtkrcv differ diff --git a/tools/bin/rtklib_b34j/aarch64/str2str b/tools/bin/rtklib_b34j/aarch64/str2str new file mode 100755 index 00000000..5c83f2e1 Binary files /dev/null and b/tools/bin/rtklib_b34j/aarch64/str2str differ diff --git a/tools/bin/rtklib_b34i/armv7l/compiled_with_buster b/tools/bin/rtklib_b34j/armv6l/compiled_with_buster similarity index 100% rename from tools/bin/rtklib_b34i/armv7l/compiled_with_buster rename to tools/bin/rtklib_b34j/armv6l/compiled_with_buster diff --git a/tools/bin/rtklib_b34j/armv6l/convbin b/tools/bin/rtklib_b34j/armv6l/convbin new file mode 100755 index 00000000..51302dc7 Binary files /dev/null and b/tools/bin/rtklib_b34j/armv6l/convbin differ diff --git a/tools/bin/rtklib_b34j/armv6l/rtkrcv b/tools/bin/rtklib_b34j/armv6l/rtkrcv new file mode 100755 index 00000000..493aba6e Binary files /dev/null and b/tools/bin/rtklib_b34j/armv6l/rtkrcv differ diff --git a/tools/bin/rtklib_b34j/armv6l/str2str b/tools/bin/rtklib_b34j/armv6l/str2str new file mode 100755 index 00000000..26580694 Binary files /dev/null and b/tools/bin/rtklib_b34j/armv6l/str2str differ diff --git a/tools/bin/rtklib_b34j/armv7l/compiled_with_buster b/tools/bin/rtklib_b34j/armv7l/compiled_with_buster new file mode 100644 index 00000000..e69de29b diff --git a/tools/bin/rtklib_b34j/armv7l/convbin b/tools/bin/rtklib_b34j/armv7l/convbin new file mode 100755 index 00000000..6cc2b1b2 Binary files /dev/null and b/tools/bin/rtklib_b34j/armv7l/convbin differ diff --git a/tools/bin/rtklib_b34j/armv7l/rtkrcv b/tools/bin/rtklib_b34j/armv7l/rtkrcv new file mode 100755 index 00000000..ffd3673f Binary files /dev/null and b/tools/bin/rtklib_b34j/armv7l/rtkrcv differ diff --git a/tools/bin/rtklib_b34j/armv7l/str2str b/tools/bin/rtklib_b34j/armv7l/str2str new file mode 100755 index 00000000..d1a09b3d Binary files /dev/null and b/tools/bin/rtklib_b34j/armv7l/str2str differ diff --git a/tools/convbin.sh b/tools/convbin.sh index ddae8d3f..4732b4d2 100755 --- a/tools/convbin.sh +++ b/tools/convbin.sh @@ -33,7 +33,7 @@ convert_to_rinex_ign() { -hp "${ANT_POSITION}" -ha 0000/"${ANT_TYPE}" \ -hr 0000/"${RECEIVER}"/"${REC_VERSION}" \ -f 2 -y R -y E -y J -y S -y C -y I \ - -od -os -oi -ot -ti 30 -tt 0 \ + -od -os -oi -ot -ti 30 -tt 0.005 \ -ro "${REC_OPTION}" -o "${RINEX_FILE}" return $? } diff --git a/tools/create_release.sh b/tools/create_release.sh index 6efe4089..c69e8c19 100755 --- a/tools/create_release.sh +++ b/tools/create_release.sh @@ -27,6 +27,7 @@ tar --exclude-vcs \ --exclude='test.sh' \ --exclude='test.conf' \ --exclude='*.pyc' \ + --exclude='rtkbase/venv' \ $TAR_ARG $ARCHIVE_NAME rtkbase/ echo '========================================================' diff --git a/tools/install.sh b/tools/install.sh index 8c0f2c44..8db3d5e4 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -37,8 +37,8 @@ man_help(){ echo ' Install all dependencies like git build-essential python3-pip ...' echo '' echo ' -r | --rtklib' - echo ' Get RTKlib 2.4.3b34i from github and compile it.' - echo ' https://github.com/rtklibexplorer/RTKLIB/tree/b34i' + echo ' Get RTKlib 2.4.3b34j from github and compile it.' + echo ' https://github.com/rtklibexplorer/RTKLIB/tree/b34j' echo '' echo ' -b | --rtkbase-release' echo ' Get last release of RTKBase:' @@ -104,7 +104,7 @@ install_dependencies() { echo 'INSTALLING DEPENDENCIES' echo '################################' apt-get "${APT_TIMEOUT}" update -y || exit 1 - apt-get "${APT_TIMEOUT}" install -y git build-essential pps-tools python3-pip python3-venv python3-dev python3-setuptools python3-wheel python3-serial libsystemd-dev bc dos2unix socat zip unzip pkg-config psmisc proj-bin || exit 1 + apt-get "${APT_TIMEOUT}" install -y git build-essential pps-tools python3-pip python3-venv python3-dev python3-setuptools python3-wheel python3-serial libsystemd-dev bc dos2unix socat zip unzip pkg-config psmisc proj-bin nftables || exit 1 apt-get install -y libxml2-dev libxslt-dev || exit 1 # needed for lxml (for pystemd) #apt-get "${APT_TIMEOUT}" upgrade -y } @@ -113,7 +113,7 @@ install_gpsd_chrony() { echo '################################' echo 'CONFIGURING FOR USING GPSD + CHRONY' echo '################################' - apt-get "${APT_TIMEOUT}" install chrony -y || exit 1 + apt-get "${APT_TIMEOUT}" install chrony gpsd -y || exit 1 #Disabling and masking systemd-timesyncd systemctl stop systemd-timesyncd systemctl disable systemd-timesyncd @@ -129,21 +129,6 @@ install_gpsd_chrony() { cp /lib/systemd/system/chrony.service /etc/systemd/system/chrony.service sed -i s/^After=.*/After=gpsd.service/ /etc/systemd/system/chrony.service - #If needed, adding backports repository to install a gpsd release that support the F9P - if lsb_release -sc | grep -qE 'bionic|buster' - then - if ! apt-cache policy | grep -qE 'buster-backports.* armhf' - then - #Adding buster-backports - echo 'deb http://httpredir.debian.org/debian buster-backports main contrib' > /etc/apt/sources.list.d/backports.list - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138 - apt-get "${APT_TIMEOUT}" update || exit 1 - fi - apt-get "${APT_TIMEOUT}" -t buster-backports install gpsd -y || exit 1 - else - #We hope that the release is more recent than buster and provide gpsd 3.20 or > - apt-get "${APT_TIMEOUT}" install gpsd -y || exit 1 - fi #disable hotplug sed -i 's/^USBAUTO=.*/USBAUTO="false"/' /etc/default/gpsd #Setting correct input for gpsd @@ -175,19 +160,19 @@ install_rtklib() { echo '################################' arch_package=$(uname -m) #[[ $arch_package == 'x86_64' ]] && arch_package='x86' - computer_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) + [[ -f /sys/firmware/devicetree/base/model ]] && computer_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) # convert "Raspberry Pi 3 Model B plus rev 1.3" or other Raspi model to the variable "Raspberry Pi" [ -n "${computer_model}" ] && [ -z "${computer_model##*'Raspberry Pi'*}" ] && computer_model='Raspberry Pi' - sbc_array=('Xunlong Orange Pi Zero' 'Raspberry Pi') + sbc_array=('Xunlong Orange Pi Zero' 'Raspberry Pi' 'OrangePi Zero3') #test if computer_model in sbc_array (https://stackoverflow.com/questions/3685970/check-if-a-bash-array-contains-a-value) if printf '%s\0' "${sbc_array[@]}" | grep -Fxqz -- "${computer_model}" \ - && [[ -f "${rtkbase_path}"'/tools/bin/rtklib_b34i/'"${arch_package}"'/str2str' ]] \ + && [[ -f "${rtkbase_path}"'/tools/bin/rtklib_b34j/'"${arch_package}"'/str2str' ]] \ && lsb_release -c | grep -qE 'buster|bullseye|bookworm' then echo 'Copying new rtklib binary for ' "${computer_model}" ' - ' "${arch_package}" - cp "${rtkbase_path}"'/tools/bin/rtklib_b34i/'"${arch_package}"/str2str /usr/local/bin/ - cp "${rtkbase_path}"'/tools/bin/rtklib_b34i/'"${arch_package}"/rtkrcv /usr/local/bin/ - cp "${rtkbase_path}"'/tools/bin/rtklib_b34i/'"${arch_package}"/convbin /usr/local/bin/ + cp "${rtkbase_path}"'/tools/bin/rtklib_b34j/'"${arch_package}"/str2str /usr/local/bin/ + cp "${rtkbase_path}"'/tools/bin/rtklib_b34j/'"${arch_package}"/rtkrcv /usr/local/bin/ + cp "${rtkbase_path}"'/tools/bin/rtklib_b34j/'"${arch_package}"/convbin /usr/local/bin/ else echo 'No binary available for ' "${computer_model}" ' - ' "${arch_package}" '. We will build it from source' _compil_rtklib @@ -196,20 +181,20 @@ install_rtklib() { _compil_rtklib() { echo '################################' - echo 'COMPILING RTKLIB 2.4.3 b34i' + echo 'COMPILING RTKLIB 2.4.3 b34j' echo '################################' - #Get Rtklib 2.4.3 b34i release - sudo -u "${RTKBASE_USER}" wget -qO - https://github.com/rtklibexplorer/RTKLIB/archive/refs/tags/b34i.tar.gz | tar -xvz + #Get Rtklib 2.4.3 b34j release + sudo -u "${RTKBASE_USER}" wget -qO - https://github.com/rtklibexplorer/RTKLIB/archive/refs/tags/b34j.tar.gz | tar -xvz #Install Rtklib app #TODO add correct CTARGET in makefile? - make --directory=RTKLIB-b34i/app/consapp/str2str/gcc - make --directory=RTKLIB-b34i/app/consapp/str2str/gcc install - make --directory=RTKLIB-b34i/app/consapp/rtkrcv/gcc - make --directory=RTKLIB-b34i/app/consapp/rtkrcv/gcc install - make --directory=RTKLIB-b34i/app/consapp/convbin/gcc - make --directory=RTKLIB-b34i/app/consapp/convbin/gcc install + make --directory=RTKLIB-b34j/app/consapp/str2str/gcc + make --directory=RTKLIB-b34j/app/consapp/str2str/gcc install + make --directory=RTKLIB-b34j/app/consapp/rtkrcv/gcc + make --directory=RTKLIB-b34j/app/consapp/rtkrcv/gcc install + make --directory=RTKLIB-b34j/app/consapp/convbin/gcc + make --directory=RTKLIB-b34j/app/consapp/convbin/gcc install #deleting RTKLIB - rm -rf RTKLIB-b34i/ + rm -rf RTKLIB-b34j/ } _rtkbase_repo(){ @@ -366,6 +351,11 @@ rtkbase_requirements(){ sudo -u "${RTKBASE_USER}" "${python_venv}" -m pip install -r "${rtkbase_path}"/web_app/requirements.txt --extra-index-url https://www.piwheels.org/simple #when we will be able to launch the web server without root, we will use #sudo -u $(logname) python3 -m pip install -r requirements.txt --user. + + #Installing requirements for Cellular modem. Installing them during the Armbian firstrun doesn't work because the network isn't fully up. + sudo -u "${RTKBASE_USER}" "${rtkbase_path}/venv/bin/python" -m pip install nmcli --extra-index-url https://www.piwheels.org/simple + sudo -u "${RTKBASE_USER}" "${rtkbase_path}/venv/bin/python" -m pip install git+https://github.com/Stefal/sim-modem.git + } install_unit_files() { @@ -400,15 +390,18 @@ detect_gnss() { if [[ "$devname" == "bus/"* ]]; then continue; fi eval "$(udevadm info -q property --export -p "${syspath}")" if [[ -z "$ID_SERIAL" ]]; then continue; fi - if [[ "$ID_SERIAL" =~ (u-blox|skytraq) ]] + if [[ "$ID_SERIAL" =~ (u-blox|skytraq|Septentrio) ]] then detected_gnss[0]=$devname detected_gnss[1]=$ID_SERIAL #echo '/dev/'"${detected_gnss[0]}" ' - ' "${detected_gnss[1]}" + # If /dev/ttyGNSS is a symlink of the detected serial port, we've found the gnss receiver, break the loop. + # This test is useful with gnss receiver offering several serial ports (like mosaic X5). The Udev rule should symlink the right one with ttyGNSS + [[ '/dev/ttyGNSS' -ef '/dev/'"${detected_gnss[0]}" ]] && break fi done if [[ ${#detected_gnss[*]} -ne 2 ]]; then - vendor_and_product_ids=$(lsusb | grep -i "u-blox" | grep -Eo "[0-9A-Za-z]+:[0-9A-Za-z]+") + vendor_and_product_ids=$(lsusb | grep -i "u-blox\|Septentrio" | grep -Eo "[0-9A-Za-z]+:[0-9A-Za-z]+") if [[ -z "$vendor_and_product_ids" ]]; then echo 'NO USB GNSS RECEIVER DETECTED' echo 'YOU CAN REDETECT IT FROM THE WEB UI' @@ -421,10 +414,10 @@ detect_gnss() { fi fi # detection on uart port - echo '################################' - echo 'UART GNSS RECEIVER DETECTION' - echo '################################' if [[ ${#detected_gnss[*]} -ne 2 ]]; then + echo '################################' + echo 'UART GNSS RECEIVER DETECTION' + echo '################################' systemctl is-active --quiet str2str_tcp.service && sudo systemctl stop str2str_tcp.service && echo 'Stopping str2str_tcp service' for port in ttyS1 serial0 ttyS2 ttyS3 ttyS0; do for port_speed in 115200 57600 38400 19200 9600; do @@ -492,17 +485,18 @@ configure_gnss(){ echo '################################' if [ -d "${rtkbase_path}" ] then - source <( grep '=' "${rtkbase_path}"/settings.conf ) + source <( grep -v '^#' "${rtkbase_path}"/settings.conf | grep '=' ) systemctl is-active --quiet str2str_tcp.service && sudo systemctl stop str2str_tcp.service - #if the receiver is a U-Blox, launch the set_zed-f9p.sh. This script will reset the F9P and configure it with the corrects settings for rtkbase - #!!!!!!!!! CHECK THIS ON A REAL raspberry/orange Pi !!!!!!!!!!! + #if the receiver is a U-Blox F9P, launch the set_zed-f9p.sh. This script will reset the F9P and configure it with the corrects settings for rtkbase if [[ $(python3 "${rtkbase_path}"/tools/ubxtool -f /dev/"${com_port}" -s ${com_port_settings%%:*} -p MON-VER) =~ 'ZED-F9P' ]] then #get F9P firmware release firmware=$(python3 "${rtkbase_path}"/tools/ubxtool -f /dev/"${com_port}" -s ${com_port_settings%%:*} -p MON-VER | grep 'FWVER' | awk '{print $NF}') + echo 'F9P Firmware: ' "${firmware}" sudo -u "${RTKBASE_USER}" sed -i s/^receiver_firmware=.*/receiver_firmware=\'${firmware}\'/ "${rtkbase_path}"/settings.conf #configure the F9P for RTKBase "${rtkbase_path}"/tools/set_zed-f9p.sh /dev/${com_port} ${com_port_settings%%:*} "${rtkbase_path}"/receiver_cfg/U-Blox_ZED-F9P_rtkbase.cfg && \ + echo 'U-Blox F9P Successfuly configured' && \ #now that the receiver is configured, we can set the right values inside settings.conf sudo -u "${RTKBASE_USER}" sed -i s/^com_port_settings=.*/com_port_settings=\'115200:8:n:1\'/ "${rtkbase_path}"/settings.conf && \ sudo -u "${RTKBASE_USER}" sed -i s/^receiver=.*/receiver=\'U-blox_ZED-F9P\'/ "${rtkbase_path}"/settings.conf && \ @@ -512,9 +506,40 @@ configure_gnss(){ sudo -u "${RTKBASE_USER}" sed -i s/^ntrip_b_receiver_options=.*/ntrip_b_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ sudo -u "${RTKBASE_USER}" sed -i s/^local_ntripc_receiver_options=.*/local_ntripc_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ sudo -u "${RTKBASE_USER}" sed -i s/^rtcm_receiver_options=.*/rtcm_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ + sudo -u "${RTKBASE_USER}" sed -i s/^rtcm_client_receiver_options=.*/rtcm_client_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ + sudo -u "${RTKBASE_USER}" sed -i s/^rtcm_udp_svr_receiver_options=.*/rtcm_udp_svr_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ + sudo -u "${RTKBASE_USER}" sed -i s/^rtcm_udp_client_receiver_options=.*/rtcm_udp_client_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ sudo -u "${RTKBASE_USER}" sed -i s/^rtcm_serial_receiver_options=.*/rtcm_serial_receiver_options=\'-TADJ=1\'/ "${rtkbase_path}"/settings.conf && \ - + #remove SBAS Rtcm message (1107) as it is disabled in the F9P configuration. + sudo -u "${RTKBASE_USER}" sed -i -r '/^rtcm_/s/1107(\([0-9]+\))?,//' "${rtkbase_path}"/settings.conf && \ return $? + + elif [[ $(python3 "${rtkbase_path}"/tools/sept_tool.py --port /dev/ttyGNSS_CTRL --baudrate ${com_port_settings%%:*} --command get_model --retry 5) =~ 'mosaic-X5' ]] + then + #get mosaic-X5 firmware release + firmware="$(python3 "${rtkbase_path}"/tools/sept_tool.py --port /dev/ttyGNSS_CTRL --baudrate ${com_port_settings%%:*} --command get_firmware --retry 5)" || firmware='?' + echo 'Mosaic-X5 Firmware: ' "${firmware}" + sudo -u "${RTKBASE_USER}" sed -i s/^receiver_firmware=.*/receiver_firmware=\'${firmware}\'/ "${rtkbase_path}"/settings.conf + #configure the mosaic-X5 for RTKBase + echo 'Resetting the mosaic-X5 settings....' + python3 "${rtkbase_path}"/tools/sept_tool.py --port /dev/ttyGNSS_CTRL --baudrate ${com_port_settings%%:*} --command reset --retry 5 + sleep_time=30 ; echo 'Waiting '$sleep_time's for mosaic-X5 reboot' ; sleep $sleep_time + echo 'Sending settings....' + python3 "${rtkbase_path}"/tools/sept_tool.py --port /dev/ttyGNSS_CTRL --baudrate ${com_port_settings%%:*} --command send_config_file "${rtkbase_path}"/receiver_cfg/Septentrio_Mosaic-X5.cfg --store --retry 5 + if [[ $? -eq 0 ]] + then + echo 'Septentrio Mosaic-X5 successfuly configured' + systemctl list-unit-files rtkbase_gnss_web_proxy.service &>/dev/null && \ + systemctl enable --now rtkbase_gnss_web_proxy.service && \ + sudo -u "${RTKBASE_USER}" sed -i s/^com_port_settings=.*/com_port_settings=\'115200:8:n:1\'/ "${rtkbase_path}"/settings.conf && \ + sudo -u "${RTKBASE_USER}" sed -i s/^receiver=.*/receiver=\'Septentrio_Mosaic-X5\'/ "${rtkbase_path}"/settings.conf && \ + sudo -u "${RTKBASE_USER}" sed -i s/^receiver_format=.*/receiver_format=\'sbf\'/ "${rtkbase_path}"/settings.conf + return $? + else + echo 'Failed to configure the Gnss receiver' + return 1 + fi + else echo 'No Gnss receiver has been set. We can'\''t configure' return 1 @@ -573,9 +598,9 @@ _add_modem_port(){ } _configure_modem(){ - sudo -u "${RTKBASE_USER}" "${rtkbase_path}/venv/bin/python" -m pip install nmcli --extra-index-url https://www.piwheels.org/simple - python3 "${rtkbase_path}"/tools/modem_config.py --config - "${rtkbase_path}"/tools/lte_network_mgmt.sh --connection_rename --lte_priority + "${rtkbase_path}"/tools/lte_network_mgmt.sh --connection_rename + sudo -u "${RTKBASE_USER}" "${rtkbase_path}/venv/bin/python" "${rtkbase_path}"/tools/modem_config.py --config && \ + "${rtkbase_path}"/tools/lte_network_mgmt.sh --lte_priority } start_services() { @@ -583,13 +608,13 @@ start_services() { echo 'STARTING SERVICES' echo '################################' systemctl daemon-reload - systemctl enable rtkbase_web.service - systemctl start rtkbase_web.service - systemctl enable str2str_tcp.service - systemctl start str2str_tcp.service + systemctl enable --now rtkbase_web.service + systemctl enable --now str2str_tcp.service systemctl restart gpsd.service systemctl restart chrony.service - systemctl start rtkbase_archive.timer + systemctl enable --now rtkbase_archive.timer + grep -qE "^modem_at_port='/[[:alnum:]]+.*'" "${rtkbase_path}"/settings.conf && systemctl enable --now modem_check.timer + grep -q "receiver='Septentrio_Mosaic-X5'" "${rtkbase_path}"/settings.conf && systemctl enable --now rtkbase_gnss_web_proxy.service echo '################################' echo 'END OF INSTALLATION' echo 'You can open your browser to http://'"$(hostname -I)" diff --git a/tools/modem_check.py b/tools/modem_check.py new file mode 100644 index 00000000..8b185b04 --- /dev/null +++ b/tools/modem_check.py @@ -0,0 +1,112 @@ +#! /usr/bin/env python3 + +import os +import sys +import time +import nmcli +from sim_modem import * + +nmcli.disable_use_sudo() +CONN_NAME='Cellular Modem' +MODEM_PORT='/dev/ttymodemAT' +USE_PUBLIC_IP=True +def sleep(timeout, retry=10): + def the_real_decorator(function): + def wrapper(*args, **kwargs): + retries = 0 + while retries < retry: + try: + value = function(*args, **kwargs) + if value is not None: + return value + except: + print(f'{function.__name__}: Sleeping for {timeout + retries*timeout} seconds') + time.sleep(timeout + retries*timeout) + retries += 1 + + return wrapper + return the_real_decorator + +@sleep(10) +def check_modem(): + nmcli.connection.show(CONN_NAME) + if nmcli.connection.show(CONN_NAME).get("GENERAL.STATE") == 'activated': + return True + +@sleep(10, retry=2) +def check_network_registration(): + try: + modem = Modem(MODEM_PORT) + network_reg = int(modem.get_network_registration_status().split(",")[1]) + if network_reg == 1 or network_reg == 2 or network_reg == 5: + return True + else: + return False + except Exception as e: + print(e) + raise Exception + finally: + modem.close() + +@sleep(10) +def get_public_ip_address(): + try: + modem = Modem(MODEM_PORT) + public_ip = modem.get_ip_address() + + except Exception as e: + print (e) + raise Exception + finally: + modem.close() + return public_ip + +@sleep(10) +def get_in_use_ip_address(): + return nmcli.connection.show(CONN_NAME)['IP4.ADDRESS[1]'].split('/')[0] + +@sleep(10) +def ping(host): + res = os.system("ping -c 4 " + host + ' >/dev/null') + return res == 0 + +check_modem() +network_reg = check_network_registration() +ip_in_use = get_in_use_ip_address() +public_ip = get_public_ip_address() +ping_host = ping('caster.centipede.fr') or ping('pch.net') + +if ip_in_use == None or public_ip == None or network_reg == False or ping_host == False: + print("Internal Ip address in use: ", ip_in_use) + print("Modem public Ip address: ", public_ip) + print("Ping caster.centipede.fr or pch.net", ping_host) + print("Modem problem. Switching to airplane mode and back to normal") + try: + print("Connecting to modem...") + modem = Modem(MODEM_PORT) + print("Sending AT+CFUN=0") + modem.custom_read_lines('AT+CFUN=0') + time.sleep(20) + print("Sending AT+CFUN=1") + modem.custom_read_lines('AT+CFUN=1') + except Exception as e: + print(e) + finally: + modem.close() + +elif USE_PUBLIC_IP and ip_in_use != public_ip: + try: + print("Internal Ip address in use: ", ip_in_use) + print("Modem public Ip address: ", public_ip) + modem = Modem(MODEM_PORT) + modem.set_usbnetip_mode(1) + print("Request to switch to public IP address done!") + print("It could take a few minutes to be active") + except Exception as e: + print(e) + finally: + print("closing modem connexion") + modem.close() +#else: +# print("We are already using the public Ip") + diff --git a/tools/modem_config.py b/tools/modem_config.py index c695b38b..2d500d54 100755 --- a/tools/modem_config.py +++ b/tools/modem_config.py @@ -3,13 +3,14 @@ import sys import os import argparse -if os.getenv("SUDO_USER") is not None: - homedir = os.path.join("/home", os.getenv("SUDO_USER")) -else: - homedir = os.path.expanduser('~') +#if os.getenv("SUDO_USER") is not None: +# homedir = os.path.join("/home", os.getenv("SUDO_USER")) +#else: +# homedir = os.path.expanduser('~') -sys.path.insert(1, os.path.join(homedir, "sim-modem")) -from src.sim_modem import * +#sys.path.insert(1, os.path.join(homedir, "sim-modem")) +#from src.sim_modem import * +from sim_modem import * def arg_parse(): parser=argparse.ArgumentParser( @@ -67,7 +68,10 @@ def arg_parse(): print("Data network registration", modem.get_eps_network_registration_status()) print("Network mode selection: ", modem.get_network_mode()) print("Current network mode: ", modem.get_current_network_mode().name) - print("Current network name/operator: ", modem.get_network_operator()) + try: + print("Current network name/operator: ", modem.get_network_operator()) + except: + print("Current network name/operator: NO SERVICE") print("EU system information: ", modem.get_eu_system_informations()) data_mode = modem.get_data_connection_mode() if data_mode.name == 'ECM': diff --git a/tools/opizero_temp_offset.sh b/tools/opizero_temp_offset.sh index b1f13ed1..7c4ce668 100755 --- a/tools/opizero_temp_offset.sh +++ b/tools/opizero_temp_offset.sh @@ -2,7 +2,7 @@ detect_sbc_temp_offset(){ #Detect if the computer is a Orange Pi Zero, and if the cpu temps is lower than 30°C, it looks like it's a Orange Pi zero LTS with a 30°C offset - computer_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) + [[ -f /sys/firmware/devicetree/base/model ]] && computer_model=$(tr -d '\0' < /sys/firmware/devicetree/base/model) cpu_temp=$(($(cat /sys/class/thermal/thermal_zone0/temp)/1000)) if [[ $computer_model = 'Xunlong Orange Pi Zero' ]] && [[ cpu_temp -lt 30 ]] then diff --git a/tools/raw2nmea/nmea_out.conf b/tools/raw2nmea/nmea_out.conf new file mode 100644 index 00000000..32a8b90f --- /dev/null +++ b/tools/raw2nmea/nmea_out.conf @@ -0,0 +1,159 @@ +# RTKNAVI options (2020/03/31 19:18:18, v.demo5 b33a) + +pos1-posmode =single # (0:single,1:dgps,2:kinematic,3:static,4:static-start,5:movingbase,6:fixed,7:ppp-kine,8:ppp-static,9:ppp-fixed) +pos1-frequency =l1+l2+l5 # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l2+l5+l6,2:l1+l2+e5b) +pos1-soltype =forward # (0:forward,1:backward,2:combined) +pos1-elmask =15 # (deg) +pos1-snrmask_r =off # (0:off,1:on) +pos1-snrmask_b =off # (0:off,1:on) +pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0 +pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0 +pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0 +pos1-dynamics =on # (0:off,1:on) +pos1-tidecorr =off # (0:off,1:on,2:otl) +pos1-ionoopt =dual-freq # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec) +pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd) +pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom) +pos1-posopt1 =on # (0:off,1:on) +pos1-posopt2 =on # (0:off,1:on) +pos1-posopt3 =on # (0:off,1:on,2:precise) +pos1-posopt4 =on # (0:off,1:on) +pos1-posopt5 =off # (0:off,1:on) +pos1-posopt6 =off # (0:off,1:on) +pos1-exclsats = # (prn ...) +pos1-navsys =63 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp) +pos2-armode =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold) +pos2-gloarmode =fix-and-hold # (0:off,1:on,2:autocal,3:fix-and-hold) +pos2-bdsarmode =on # (0:off,1:on) +pos2-arfilter =on # (0:off,1:on) +pos2-arthres =3 +pos2-arthres1 =0.1 +pos2-arthres2 =0 +pos2-arthres3 =1e-09 +pos2-arthres4 =1e-05 +pos2-varholdamb =0.1 # (cyc^2) +pos2-gainholdamb =0.01 +pos2-arlockcnt =0 +pos2-minfixsats =4 +pos2-minholdsats =5 +pos2-mindropsats =10 +pos2-rcvstds =off # (0:off,1:on) +pos2-arelmask =15 # (deg) +pos2-arminfix =20 +pos2-armaxiter =1 +pos2-elmaskhold =15 # (deg) +pos2-aroutcnt =20 +pos2-maxage =30 # (s) +pos2-syncsol =off # (0:off,1:on) +pos2-slipthres =0.05 # (m) +pos2-rejionno =1000 # (m) +pos2-rejgdop =30 +pos2-niter =1 +pos2-baselen =0 # (m) +pos2-basesig =0 # (m) +out-solformat =llh # (0:llh,1:xyz,2:enu,3:nmea) +out-outhead =on # (0:off,1:on) +out-outopt =on # (0:off,1:on) +out-outvel =off # (0:off,1:on) +out-timesys =gpst # (0:gpst,1:utc,2:jst) +out-timeform =hms # (0:tow,1:hms) +out-timendec =3 +out-degform =deg # (0:deg,1:dms) +out-fieldsep = +out-outsingle =off # (0:off,1:on) +out-maxsolstd =0 # (m) +out-height =ellipsoidal # (0:ellipsoidal,1:geodetic) +out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) +out-solstatic =all # (0:all,1:single) +out-nmeaintv1 =0 # (s) +out-nmeaintv2 =0 # (s) +out-outstat =off # (0:off,1:state,2:residual) +stats-weightmode =elevation # (0:elevation,1:snr) +stats-eratio1 =300 +stats-eratio2 =300 +stats-eratio5 =300 +stats-errphase =0.003 # (m) +stats-errphaseel =0.003 # (m) +stats-errphasebl =0 # (m/10km) +stats-errdoppler =1 # (Hz) +stats-snrmax =52 # (dB.Hz) +stats-stdbias =30 # (m) +stats-stdiono =0.03 # (m) +stats-stdtrop =0.3 # (m) +stats-prnaccelh =3 # (m/s^2) +stats-prnaccelv =1 # (m/s^2) +stats-prnbias =0.0001 # (m) +stats-prniono =0.001 # (m) +stats-prntrop =0.0001 # (m) +stats-prnpos =0 # (m) +stats-clkstab =5e-12 # (s/s) +ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) +ant1-pos1 =90 # (deg|m) +ant1-pos2 =0 # (deg|m) +ant1-pos3 =-6335367.6285 # (m|m) +ant1-anttype = +ant1-antdele =0 # (m) +ant1-antdeln =0 # (m) +ant1-antdelu =0 # (m) +ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) +ant2-pos1 =0 # (deg|m) +ant2-pos2 =0 # (deg|m) +ant2-pos3 =0 # (m|m) +ant2-anttype = +ant2-antdele =0 # (m) +ant2-antdeln =0 # (m) +ant2-antdelu =0 # (m) +ant2-maxaveep =1 +ant2-initrst =on # (0:off,1:on) +misc-timeinterp =off # (0:off,1:on) +misc-sbasatsel =0 # (0:all) +misc-rnxopt1 = +misc-rnxopt2 = +misc-pppopt = +file-satantfile = +file-rcvantfile = +file-staposfile = +file-geoidfile = +file-ionofile = +file-dcbfile = +file-eopfile = +file-blqfile = +file-tempdir = +file-geexefile = +file-solstatfile = +file-tracefile = +# + +inpstr1-type =tcpcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) +inpstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) +inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http) +inpstr1-path =localhost:5015 +inpstr2-path = +inpstr3-path = +inpstr1-format =sbf +inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:swift,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,15:tersus,17:sp3) +inpstr3-format =rtcm2 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:swift,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,13:sbf,14:cmr,15:tersus,17:sp3) +inpstr2-nmeareq =off # (0:off,1:latlon,2:single) +inpstr2-nmealat =0 # (deg) +inpstr2-nmealon =0 # (deg) +outstr1-type =tcpsvr # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) +outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) +outstr1-path =localhost:5014 +outstr2-path = +outstr1-format =nmea # (0:llh,1:xyz,2:enu,3:nmea) +outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea) +logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) +logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) +logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr) +logstr1-path = +logstr2-path = +logstr3-path = +misc-svrcycle =10 # (ms) +misc-timeout =10000 # (ms) +misc-reconnect =10000 # (ms) +misc-nmeacycle =5000 # (ms) +misc-buffsize =32768 # (bytes) +misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr) +misc-proxyaddr = +misc-fswapmargin =30 # (s) + diff --git a/tools/raw2nmea/raw2nmea.sh b/tools/raw2nmea/raw2nmea.sh new file mode 100755 index 00000000..acdd9ab2 --- /dev/null +++ b/tools/raw2nmea/raw2nmea.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +#Script to get raw data from the gnss receiver, compute it with rtkrcv, and output to nmea on tcp port 5014, for feeding gpsd. +#Unuseful with a U-Blox receiver +#Useful with other receivers to get date time when there is no internet connection + +if [[ -z ${rtkbase_path} ]] + then + if grep -q '^rtkbase_path=' /etc/environment + then + source /etc/environment + else + echo 'Error, missing rtkbase_path variable' + exit 1 + fi + fi + +RAW_PORT=$(grep ^tcp_port= "${rtkbase_path}"/settings.conf | awk -F"'" '{print $2}') +RAW_FORMAT=$(grep ^receiver_format= "${rtkbase_path}"/settings.conf | awk -F"'" '{print $2}') +NMEA_PORT=$(grep ^nmea_port= "${rtkbase_path}"/settings.conf | awk -F"'" '{print $2}') +if [[ $RAW_FORMAT == ubx ]] + then + echo "Service not needed with ubx format" + exit +fi + +sed -i s/^inpstr1-path.*/inpstr1-path\ \ =localhost:$RAW_PORT/ "${rtkbase_path}"/tools/raw2nmea/nmea_out.conf +sed -i s/^inpstr1-format.*/inpstr1-format\ \ =$RAW_FORMAT/ "${rtkbase_path}"/tools/raw2nmea/nmea_out.conf +sed -i s/^outstr1-path.*/outstr1-path\ \ =localhost:$NMEA_PORT/ "${rtkbase_path}"/tools/raw2nmea/nmea_out.conf +sed -i 's/^DEVICES=.*/DEVICES="tcp:\/\/localhost:'$NMEA_PORT'"/' /etc/default/gpsd + +{ sleep 20 ; systemctl restart gpsd ;} & +rtkrcv -o "${rtkbase_path}"/tools/raw2nmea/nmea_out.conf -nc diff --git a/tools/sept_tool.py b/tools/sept_tool.py new file mode 100644 index 00000000..9528ecf2 --- /dev/null +++ b/tools/sept_tool.py @@ -0,0 +1,56 @@ +#! /usr/bin/env python3 + +import os +import sys +import argparse +from septentrio.septentrio_cmd import * +from enum import Enum +from operator import methodcaller + +class CmdMapping(Enum): + """Mapping human command to septentrio methods""" + + #get_model = methodcaller('get_receiver_model') + get_model = 'get_receiver_model' + get_firmware = 'get_receiver_firmware' + get_ip = 'get_receiver_ip' + reset = 'set_factory_default' + send_config_file = 'send_config_file' + +def arg_parse(): + """ Parse the command line you use to launch the script """ + + parser= argparse.ArgumentParser(prog='Septentrio tool', description="A tool to send comment to a Septentrio GNSS receiver") + parser.add_argument("-p", "--port", help="Port to connect to", type=str) + parser.add_argument("-b", "--baudrate", help="port baudrate", default=115200, type=int) + parser.add_argument("-c", "--command", nargs='+', help="Command to send to the gnss receiver", type=str) + parser.add_argument("-s", "--store", action='store_true', help="Store settings as permanent", default=False) + parser.add_argument("-r", "--retry", help="set a number of retry if the command fails", default=0, type=int) + parser.add_argument("--version", action="version", version="%(prog)s 1.0") + args = parser.parse_args() + #print(args) + return args + +if __name__ == '__main__': + args = arg_parse() + #print(args) + command = args.command[0] + retries = 0 + retry_delay = 10 + while retries <= args.retry: + try: + with SeptGnss(args.port, baudrate=args.baudrate, timeout=30, debug=False) as gnss: + res = methodcaller(CmdMapping[command].value, *args.command[1:])(gnss) + if type(res) is str: + print(res) + if args.store: + gnss.set_config_permanent() + #methodcaller(args.command[0])(gnss) + break + except: + retries += 1 + print("Failed...retrying in {}s".format(retry_delay)) + time.sleep(retry_delay) + if retries > args.retry: + print("Command failed!") + sys.exit(1) \ No newline at end of file diff --git a/tools/septentrio/__init__.py b/tools/septentrio/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/septentrio/septentrio_cmd.py b/tools/septentrio/septentrio_cmd.py new file mode 100644 index 00000000..4fbb104a --- /dev/null +++ b/tools/septentrio/septentrio_cmd.py @@ -0,0 +1,154 @@ +#! /usr/bin/env python3 +from . serial_comm import SerialComm +from enum import Enum +from logging import getLogger +import xml.etree.ElementTree as ET +import time +#Code inspired by https://github.com/jonamat/sim-modem + +class SeptGnss: + """Class for sending command to Septentrio Gnss receivers""" + + def __init__( + self, + address, + baudrate=115200, + timeout=2, + cmd_delay=0.1, + debug=False, + ): + self.comm = SerialComm( + address=address, + baudrate=baudrate, + timeout=timeout, + cmd_delay=cmd_delay, + connection_descriptor='USB2>', + ) + self.debug = debug + self.connect() + + def connect(self) -> None: + self.comm.send('exeEchoMessage, COM1, "A:HELLO", none') + read = self.comm.read_raw(1000) + try: + check_hello = b"A:HELLO" in read + res_descriptor = read.decode().split()[-1] + check_descriptor = 'COM' in res_descriptor or 'USB' in res_descriptor or 'IP1' in res_descriptor + if check_hello and check_descriptor: + self.comm.connection_descriptor = read.decode().split()[-1] + else: + raise Exception + if self.debug: + print("GNSS receiver connected, debug mode enabled") + print("Connection descriptor: {}".format(self.comm.connection_descriptor)) + except Exception: + print("GNSS receiver did not respond correctly") + if self.debug: + print(read) + self.close() + + def close(self) -> None: + self.comm.close() + + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, exception_traceback): + self.close() + + # --------------------------------- Common methods --------------------------------- # + + def get_receiver_model(self) -> str: + read = self.send_read_until('lstInternalFile', 'Identification') + model = self.__parse_rcv_info(read, 'hwplatform', 'product') + return model + + def get_receiver_firmware(self) -> str: + read = self.send_read_until('lstInternalFile', 'Identification') + firmware = self.__parse_rcv_info(read, 'firmware', 'version') + return firmware + + def get_receiver_ip(self) -> str: + read = self.send_read_until('lstInternalFile', 'IPParameters') + ip_addr = self.__parse_rcv_info(read, 'inet', 'addr') + return ip_addr + + def __parse_rcv_info(self, pseudo_xml, element_tag, info) -> str: + ''' + This methode will try to parse the xml file received + when we send the lstInternalFile command + ''' + pseudo_xml = [line for line in pseudo_xml[2:-1] if not (line.startswith('$') or line == '---->')] + e = ET.ElementTree(ET.fromstring(''.join(pseudo_xml))) + res_info = None + for element in e.iter(): + #print(element.tag, element.attrib, element.text) + res_info = element.get(info) if element_tag in element.tag and element.get(info) else res_info + return res_info + + def get_port_applications(self, port) -> str: + read = self.send_read_until('getRegisteredApplications', port) + return read[-2].split(',')[-1].replace('"','').strip() + + def set_port_applications(self, port, applications_name) -> None: + read = self.send_read_until('exeRegisteredApplications', port, applications_name) + + def set_factory_default(self) -> None: + ''' + Reset receiver settings to factory defaults and restart it + Connection will be closed + ''' + if self.debug: + print("Sending: 'exeResetReceiver, Soft, Config'") + self.comm.send('exeResetReceiver, Soft, Config') + read = self.comm.read_until('STOP>') + if self.debug: + print("Receiving: {}".format(read)) + if read[-1] != 'STOP>' or read[0].startswith('$R?'): + raise Exception("Command failed!\nSent: 'exeResetReceiver, Soft, Config'\nReceived: {}".format(read)) + self.close() + print("Connection closed") + + def send_config_file(self, file, perm=False) -> None: + ''' + Send user commands from a txt file, line by line + Set perm to True if you want to set these settings permanent + ''' + with open(file, 'r') as f: + for line in f: + if line.strip() != '' and not line.startswith('#'): + cmd,*args = line.split(',') + #print(cmd, args) + self.send_read_until(cmd + ', ' + ', '.join(args)) + if perm: + self.set_config_permanent() + + def set_config_permanent(self) -> None: + ''' + Save current settings to boot config + ''' + read = self.send_read_until('exeCopyConfigFile', 'Current', 'Boot') + + # ----------------------------------- OTHERS --------------------------------- # + + def send_read_lines(self, cmd, *args) -> list: + if self.debug: + print("Sending: {}{}{}".format(cmd, ', ' if args else '', ', '.join(args))) + self.comm.send("{}{}{}".format(cmd, ', ' if args else '', ', '.join(args))) + read = self.comm.read_lines() + if self.debug: + print("Receiving: {}".format(read)) + if read[-1] != self.comm.connection_descriptor or read[0].startswith('$R?'): + raise Exception("Command failed!\nSent: {}\nReceived: {}".format((cmd + ', ' + ', '.join(args)), read)) + return read + + def send_read_until(self, cmd, *args) -> list: + if self.debug: + print("Sending: {}{}{}".format(cmd, ', ' if args else '', ', '.join(args))) + self.comm.send("{}{}{}".format(cmd, ', ' if args else '', ', '.join(args))) + read = self.comm.read_until() + if self.debug: + print("Receiving: {}".format(read)) + if read[-1] != self.comm.connection_descriptor or read[0].startswith('$R?'): + raise Exception("Command failed!\nSent: {}\nReceived: {}".format((cmd + ', ' + ', '.join(args)), read)) + return read diff --git a/tools/septentrio/serial_comm.py b/tools/septentrio/serial_comm.py new file mode 100644 index 00000000..dc694734 --- /dev/null +++ b/tools/septentrio/serial_comm.py @@ -0,0 +1,54 @@ +#! /usr/bin/env python3 +import serial +import time + + +class SerialComm: + def __init__( + self, + address, + baudrate=115200, + timeout=5, + write_timeout=5, + cmd_delay=0.1, + connection_descriptor='USB2>', + on_error=None, + byte_encoding="ISO-8859-1", + ): + self.cmd_delay = cmd_delay + self.connection_descriptor = connection_descriptor + self.on_error = on_error + self.byte_encoding = byte_encoding + self.device_serial = serial.Serial( + port=address, + baudrate=baudrate, + timeout=timeout, + write_timeout=write_timeout + ) + + def send(self, cmd) -> str: + self.device_serial.write(cmd.encode(self.byte_encoding) + b"\r") + time.sleep(self.cmd_delay) + + def send_raw(self, cmd): + self.device_serial.write(cmd) + time.sleep(self.cmd_delay) + + def read_lines(self) -> list: + read = self.device_serial.readlines() + for i, line in enumerate(read): + read[i] = line.decode(self.byte_encoding).strip() + return read + + def read_until(self, expect = None) -> list: + expect = self.connection_descriptor if expect == None else expect + read = self.device_serial.read_until(expected=bytes(expect, encoding=self.byte_encoding)) + read = read.decode(self.byte_encoding).strip().splitlines() + read = [ val for val in read if val != ''] + return read + + def read_raw(self, size: int): + return self.device_serial.read(size) + + def close(self): + self.device_serial.close() \ No newline at end of file diff --git a/tools/switch_to_public_ip.py b/tools/switch_to_public_ip.py deleted file mode 100644 index c857045d..00000000 --- a/tools/switch_to_public_ip.py +++ /dev/null @@ -1,62 +0,0 @@ -#! /usr/bin/env python3 - -import os -import sys -import nmcli -if os.getenv("SUDO_USER") is not None: - homedir = os.path.join("/home", os.getenv("SUDO_USER")) -else: - homedir = os.path.expanduser('~') - -sys.path.insert(1, os.path.join(homedir, "sim-modem")) -from src.sim_modem import * - -nmcli.disable_use_sudo() -CONN_NAME='Cellular Modem' - -def sleep(timeout, retry=50): - def the_real_decorator(function): - def wrapper(*args, **kwargs): - retries = 0 - while retries < retry: - try: - value = function(*args, **kwargs) - if value is not None: - return value - except: - print(f'Sleeping for {timeout + retries*timeout} seconds') - time.sleep(timeout + retries*timeout) - retries += 1 - - return wrapper - return the_real_decorator - -@sleep(10) -def check_modem(): - nmcli.connection.show(CONN_NAME) - if nmcli.connection.show(CONN_NAME).get("GENERAL.STATE") == 'activated': - return True - -@sleep(10) -def get_public_ip_address(): - return modem.get_ip_address() - -@sleep(10) -def get_in_use_ip_address(): - return nmcli.connection.show(CONN_NAME)['IP4.ADDRESS[1]'].split('/')[0] - -check_modem() -modem = Modem('/dev/ttymodemAT') -ip_in_use = get_in_use_ip_address() -public_ip = get_public_ip_address() - -print("Ip address in use: ", ip_in_use) -print("Public Ip address: ", public_ip) - -if ip_in_use != public_ip: - modem.set_usbnetip_mode(1) - print("Request to switch to public IP address done!") - print("It could take a few minutes to be active") -else: - print("We are already using the public Ip") - diff --git a/tools/udev_rules/91-gnss.rules b/tools/udev_rules/91-gnss.rules index c9baa220..87d11a69 100644 --- a/tools/udev_rules/91-gnss.rules +++ b/tools/udev_rules/91-gnss.rules @@ -1 +1,7 @@ +#U-Blox F9P SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="ttyGNSS" + +#Septentrio +SUBSYSTEM=="tty", ATTRS{idVendor}=="152a", ATTRS{idProduct}=="85c0", ENV{USB_TYPE}="152a:85c0" +ENV{USB_TYPE}=="152a:85c0", SUBSYSTEM=="tty", ATTRS{bInterfaceNumber}=="02", GROUP="dialout", SYMLINK+="ttyGNSS" +ENV{USB_TYPE}=="152a:85c0", SUBSYSTEM=="tty", ATTRS{bInterfaceNumber}=="04", MODE="0660", GROUP="dialout", SYMLINK+="ttyGNSS_CTRL" diff --git a/tools/uninstall.sh b/tools/uninstall.sh index dde38774..37d86d40 100755 --- a/tools/uninstall.sh +++ b/tools/uninstall.sh @@ -8,13 +8,17 @@ for service_name in str2str_tcp.service \ str2str_ntrip_B.service \ str2str_local_ntrip_caster \ str2str_rtcm_svr.service \ + str2str_rtcm_client.service \ + str2str_rtcm_udp_svr.service \ + str2str_rtcm_udp_client.service \ str2str_rtcm_serial.service \ str2str_file.service \ rtkbase_web \ rtkbase_archive.service \ rtkbase_archive.timer \ - modem_public_ip.service \ - modem_public_ip.timer + modem_check.service \ + modem_check.timer \ + rtkbase_gnss_web_proxy.service do echo 'Deleting ' "${service_name}" systemctl stop "${service_name}" diff --git a/unit/disabled/rtkbase_update.service b/unit/disabled/rtkbase_update.service new file mode 100644 index 00000000..416b4fc7 --- /dev/null +++ b/unit/disabled/rtkbase_update.service @@ -0,0 +1,12 @@ +[Unit] +Description=RTKBase update service + + +[Service] +User=root +Type=oneshot +EnvironmentFile=/home/stephane/gnss_venv/rtkbase/tools/service_args.conf +ExecStart=/var/tmp/rtkbase_update.sh ${ARG1} ${ARG2} ${ARG3} ${ARG4} ${ARG5} + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/unit/disabled/str2str_rtcm_client.service b/unit/disabled/str2str_rtcm_client.service new file mode 100644 index 00000000..f7101fc6 --- /dev/null +++ b/unit/disabled/str2str_rtcm_client.service @@ -0,0 +1,21 @@ +[Unit] +Description=RTKBase RTCM Client +#After=network-online.target +#Wants=network-online.target +Requires=str2str_tcp.service + +[Service] +Type=forking +User={user} +ExecStart={script_path}/run_cast.sh in_tcp out_rtcm_client +Restart=on-failure +RestartSec=30 +#Limiting log to 1 msg per minute +LogRateLimitIntervalSec=1 minute +LogRateLimitBurst=1 +ProtectHome=read-only +ProtectSystem=strict +ReadWritePaths={script_path} + +[Install] +WantedBy=multi-user.target diff --git a/unit/disabled/str2str_rtcm_udp_client.service b/unit/disabled/str2str_rtcm_udp_client.service new file mode 100644 index 00000000..d4a0c4c2 --- /dev/null +++ b/unit/disabled/str2str_rtcm_udp_client.service @@ -0,0 +1,21 @@ +[Unit] +Description=RTKBase RTCM UDP Client +#After=network-online.target +#Wants=network-online.target +Requires=str2str_tcp.service + +[Service] +Type=forking +User={user} +ExecStart={script_path}/run_cast.sh in_tcp out_rtcm_udp_client +Restart=on-failure +RestartSec=30 +#Limiting log to 1 msg per minute +LogRateLimitIntervalSec=1 minute +LogRateLimitBurst=1 +ProtectHome=read-only +ProtectSystem=strict +ReadWritePaths={script_path} + +[Install] +WantedBy=multi-user.target diff --git a/unit/disabled/str2str_rtcm_udp_svr.service b/unit/disabled/str2str_rtcm_udp_svr.service new file mode 100644 index 00000000..e7ce44d8 --- /dev/null +++ b/unit/disabled/str2str_rtcm_udp_svr.service @@ -0,0 +1,21 @@ +[Unit] +Description=RTKBase RTCM UDP Server +#After=network-online.target +#Wants=network-online.target +Requires=str2str_tcp.service + +[Service] +Type=forking +User={user} +ExecStart={script_path}/run_cast.sh in_tcp out_rtcm_udp_svr +Restart=on-failure +RestartSec=30 +#Limiting log to 1 msg per minute +LogRateLimitIntervalSec=1 minute +LogRateLimitBurst=1 +ProtectHome=read-only +ProtectSystem=strict +ReadWritePaths={script_path} + +[Install] +WantedBy=multi-user.target diff --git a/unit/modem_check.service b/unit/modem_check.service new file mode 100644 index 00000000..d83ed587 --- /dev/null +++ b/unit/modem_check.service @@ -0,0 +1,13 @@ +[Unit] +Description=Check Simcom modem status +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User={user} +ExecStart={python_path} {script_path}/tools/modem_check.py +Restart=on-failure +RestartSec=30 +ProtectHome=read-only +ProtectSystem=strict diff --git a/unit/modem_public_ip.timer b/unit/modem_check.timer similarity index 60% rename from unit/modem_public_ip.timer rename to unit/modem_check.timer index 660e6acf..5a075f6d 100644 --- a/unit/modem_public_ip.timer +++ b/unit/modem_check.timer @@ -1,7 +1,8 @@ [Unit] -Description=Run modem_public_ip.service every hour +Description=Run modem_check.service every hour [Timer] +OnBootSec=30 OnCalendar=*-*-* *:00:00 Persistent=true diff --git a/unit/modem_public_ip.service b/unit/modem_public_ip.service deleted file mode 100644 index a740967c..00000000 --- a/unit/modem_public_ip.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Switch Simcom modem to public ip address -After=network-online.target -Wants=network-online.target - -[Service] -Type=forking -User={user} -ExecStart={python_path} {script_path}/tools/switch_to_public_ip.py -Restart=on-failure -RestartSec=30 -ProtectHome=read-only -ProtectSystem=strict - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/unit/rtkbase_gnss_web_proxy.service b/unit/rtkbase_gnss_web_proxy.service new file mode 100644 index 00000000..f3170bbe --- /dev/null +++ b/unit/rtkbase_gnss_web_proxy.service @@ -0,0 +1,16 @@ +[Unit] +Description=RTKBase Reverse Proxy for Gnss receiver Web Server +#After=network-online.target +#Wants=network-online.target + +[Service] +User={user} +ExecStart={python_path} {script_path}/web_app/gnss_rproxy_server.py +Restart=on-failure +RestartSec=30 +ProtectHome=read-only +ProtectSystem=strict +ReadWritePaths={script_path} /usr/local/bin /var/tmp + +[Install] +WantedBy=multi-user.target diff --git a/unit/rtkbase_raw2nmea.service b/unit/rtkbase_raw2nmea.service new file mode 100644 index 00000000..ee8ec723 --- /dev/null +++ b/unit/rtkbase_raw2nmea.service @@ -0,0 +1,14 @@ +[Unit] +Description=RTKBase - Convert Gnss Raw data to nmea output on tcp +Requires=str2str_tcp.service + +[Service] +Type=simple +User=root +ExecStart={script_path}/tools/raw2nmea/raw2nmea.sh +ProtectHome=read-only +ProtectSystem=strict +ReadWritePaths={script_path} /etc/default + +[Install] +WantedBy=multi-user.target diff --git a/web_app/RTKBaseConfigManager.py b/web_app/RTKBaseConfigManager.py index f365c973..eabd3032 100644 --- a/web_app/RTKBaseConfigManager.py +++ b/web_app/RTKBaseConfigManager.py @@ -110,7 +110,7 @@ def get_main_settings(self): and remove the single quotes. """ ordered_main = [{"source_section" : "main"}] - for key in ("position", "com_port", "com_port_settings", "receiver", "receiver_firmware", "receiver_format", "antenna_info", "tcp_port"): + for key in ("position", "com_port", "com_port_settings", "receiver", "receiver_firmware", "receiver_format", "antenna_info", "tcp_port", "gnss_rcv_web_ip", "gnss_rcv_web_proxy_port"): ordered_main.append({key : self.config.get('main', key).strip("'")}) return ordered_main @@ -165,6 +165,36 @@ def get_rtcm_svr_settings(self): ordered_rtcm_svr.append({key : self.config.get('rtcm_svr', key).strip("'")}) return ordered_rtcm_svr + def get_rtcm_client_settings(self): + """ + Get a subset of the settings from the file section in an ordered object + and remove the single quotes. + """ + ordered_rtcm_client = [{"source_section" : "rtcm_client"}] + for key in ("rtcm_client_addr", "rtcm_client_port", "rtcm_client_user", "rtcm_client_pwd", "rtcm_client_msg", "rtcm_client_receiver_options"): + ordered_rtcm_client.append({key : self.config.get('rtcm_client', key).strip("'")}) + return ordered_rtcm_client + + def get_rtcm_udp_svr_settings(self): + """ + Get a subset of the settings from the file section in an ordered object + and remove the single quotes. + """ + ordered_rtcm_udp_svr = [{"source_section" : "rtcm_udp_svr"}] + for key in ("rtcm_udp_svr_port", "rtcm_udp_svr_msg", "rtcm_udp_svr_receiver_options"): + ordered_rtcm_udp_svr.append({key : self.config.get('rtcm_udp_svr', key).strip("'")}) + return ordered_rtcm_udp_svr + + def get_rtcm_udp_client_settings(self): + """ + Get a subset of the settings from the file section in an ordered object + and remove the single quotes. + """ + ordered_rtcm_udp_client = [{"source_section" : "rtcm_udp_client"}] + for key in ("rtcm_udp_client_addr", "rtcm_udp_client_port", "rtcm_udp_client_msg", "rtcm_udp_client_receiver_options"): + ordered_rtcm_udp_client.append({key : self.config.get('rtcm_udp_client', key).strip("'")}) + return ordered_rtcm_udp_client + def get_rtcm_serial_settings(self): """ Get a subset of the settings from the file section in an ordered object @@ -187,6 +217,9 @@ def get_ordered_settings(self): ordered_settings['local_ntripc'] = self.get_local_ntripc_settings() ordered_settings['file'] = self.get_file_settings() ordered_settings['rtcm_svr'] = self.get_rtcm_svr_settings() + ordered_settings['rtcm_client'] = self.get_rtcm_client_settings() + ordered_settings['rtcm_udp_svr'] = self.get_rtcm_udp_svr_settings() + ordered_settings['rtcm_udp_client'] = self.get_rtcm_udp_client_settings() ordered_settings['rtcm_serial'] = self.get_rtcm_serial_settings() return ordered_settings diff --git a/web_app/gnss_rproxy_server.py b/web_app/gnss_rproxy_server.py new file mode 100644 index 00000000..7c08a6e8 --- /dev/null +++ b/web_app/gnss_rproxy_server.py @@ -0,0 +1,199 @@ +#!/usr/bin/python + +# author: Stéphane Péneau +# source: https://github.com/Stefal/rtkbase + +# Reverse proxy server to acces a Gnss receiver integrated Web Server (Mosaic-X5 or other) + +import os +from gevent import monkey +monkey.patch_all() +import requests +import argparse + +from RTKBaseConfigManager import RTKBaseConfigManager +#from dotenv import load_dotenv # pip package python-dotenv + +from flask_bootstrap import Bootstrap4 +from flask import Flask, render_template, session, request, flash, url_for, Response +from flask import redirect, abort +from flask import g +from flask_wtf import FlaskForm +from wtforms import PasswordField, BooleanField, SubmitField +from flask_login import LoginManager, login_user, logout_user, login_required, current_user, UserMixin +from wtforms.validators import ValidationError, DataRequired, EqualTo +import urllib +import gunicorn.app.base + +from werkzeug.security import generate_password_hash +from werkzeug.security import check_password_hash +from werkzeug.utils import safe_join + + +app = Flask(__name__) +app.debug = False +app.config["SECRET_KEY"] = "secret!" +app.config["LOGIN_DISABLED"] = False + +rtkbase_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../")) + +login=LoginManager(app) +login.login_view = 'login_page' +bootstrap = Bootstrap4(app) + +#Get settings from settings.conf.default and settings.conf +rtkbaseconfig = RTKBaseConfigManager(os.path.join(rtkbase_path, "settings.conf.default"), os.path.join(rtkbase_path, "settings.conf")) +GNSS_RCV_WEB_URL = str("{}{}".format("http://", rtkbaseconfig.get("main", "gnss_rcv_web_ip"))) + +class StandaloneApplication(gunicorn.app.base.BaseApplication): + def __init__(self, app, options=None): + self.options = options or {} + self.application = app + super().__init__() + + def load_config(self): + config = {key: value for key, value in self.options.items() + if key in self.cfg.settings and value is not None} + for key, value in config.items(): + self.cfg.set(key.lower(), value) + + def load(self): + return self.application + +class User(UserMixin): + """ Class for user authentification """ + def __init__(self, username): + self.id=username + self.password_hash = rtkbaseconfig.get("general", "web_password_hash") + + def check_password(self, password): + return check_password_hash(self.password_hash, password) + +class LoginForm(FlaskForm): + """ Class for the loginform""" + #username = StringField('Username', validators=[DataRequired()]) + password = PasswordField('Please enter the RTKBase password:', validators=[DataRequired()]) + remember_me = BooleanField('Remember Me') + submit = SubmitField('Sign In') + +@app.before_request +def inject_release(): + """ + Insert the RTKBase release number as a global variable for Flask/Jinja + """ + g.version = rtkbaseconfig.get("general", "version") + +@login.user_loader +def load_user(id): + return User(id) + +#proxy code from https://stackoverflow.com/a/36601467 +@app.route('/', defaults={'path': ''}, methods=["GET", "POST"]) # ref. https://medium.com/@zwork101/making-a-flask-proxy-server-online-in-10-lines-of-code-44b8721bca6 +@app.route('/', methods=["GET", "POST"]) # NOTE: better to specify which methods to be accepted. Otherwise, only GET will be accepted. Ref: +@login_required +def redirect_to_API_HOST(path): #NOTE var :path will be unused as all path we need will be read from :request ie from flask import request + res = requests.request( # ref. https://stackoverflow.com/a/36601467/248616 + method = request.method, + url = request.url.replace(request.host_url, f'{GNSS_RCV_WEB_URL}/'), + headers = {k:v for k,v in request.headers if k.lower() != 'host'}, # exclude 'host' header + data = request.get_data(), + cookies = request.cookies, + allow_redirects = False, + ) + """ print("method: ", request.method) + print("request posturl: ", request.url) + print("request host: ", request.host_url) + print("url: ", request.url.replace(request.host_url, f'{GNSS_RCV_WEB_URL}/')) + print("header: ", {k:v for k,v in request.headers if k.lower() != 'host'}) + print("data: ", request.get_data()) + print("cookies: ", request.cookies) + print("host url split", urllib.parse.urlsplit(request.host_url)) + print("host url split2", urllib.parse.urlsplit(request.base_url).hostname) + old = urllib.parse.urlparse(request.host_url) + new = urllib.parse.ParseResult(scheme=old.scheme, netloc="{}:{}".format(old.hostname, 9090), + path=old.path, params=old.params, query=old.query, fragment=old.fragment) + print("new_url: ", new.geturl()) """ + #region exlcude some keys in :res response + excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] #NOTE we here exclude all "hop-by-hop headers" defined by RFC 2616 section 13.5.1 ref. https://www.rfc-editor.org/rfc/rfc2616#section-13.5.1 + headers = [ + (k,v) for k,v in res.raw.headers.items() + if k.lower() not in excluded_headers + ] + #endregion exlcude some keys in :res response + + response = Response(res.content, res.status_code, headers) + return response + + +@app.route('/login', methods=['GET', 'POST']) +def login_page(): + if current_user.is_authenticated: + return redirect(url_for('index')) + + loginform = LoginForm() + if loginform.validate_on_submit(): + user = User('admin') + password = loginform.password.data + if not user.check_password(password): + return abort(401) + + login_user(user, remember=loginform.remember_me.data) + next_page = request.args.get('redirect_to_API_HOST') + if not next_page or urllib.parse.urlsplit(next_page).netloc != '': + next_page = url_for('redirect_to_API_HOST') + + return redirect(next_page) + + return render_template('proxy_login.html', title='Sign In', form=loginform) + +@app.route('/logout') +def logout(): + logout_user() + return redirect(url_for('login_page')) + +def arg_parse(): + parser = argparse.ArgumentParser( + description="RTKBase Gnss Web proxy server", + formatter_class=argparse.RawTextHelpFormatter, + ) + parser.add_argument( + "-d", + "--debug", + help="Enable web server debug mode", + action="store_true", + default=False, + ) + parser.add_argument( + "-p", + "--port", + type=int, + help="port used for the web server", + default=None + ) + args = parser.parse_args() + return args + +if __name__ == "__main__": + args=arg_parse() + try: + #check if authentification is required + if not rtkbaseconfig.get_web_authentification(): + app.config["LOGIN_DISABLED"] = True + + app.secret_key = rtkbaseconfig.get_secret_key() + #socketio.run(app, host = "::", port = args.port or rtkbaseconfig.get("general", "web_port", fallback=80), debug=args.debug) # IPv6 "::" is mapped to IPv4 + #wsgi.server(eventlet.listen(("0.0.0.0", int(rtkbaseconfig.get("main", "gnss_rcv_web_proxy_port", fallback=9090)))), app, log_output=False) + + gunicorn_options = { + 'bind': ['%s:%s' % ('0.0.0.0', args.port or rtkbaseconfig.get("main", "gnss_rcv_web_proxy_port", fallback=9090)), + '%s:%s' % ('[::1]', args.port or rtkbaseconfig.get("main", "gnss_rcv_web_proxy_port", fallback=9090)) ], + 'workers': 1, + 'worker_class': 'gevent', + 'loglevel': 'debug' if args.debug else 'warning', + } + #start gunicorn + StandaloneApplication(app, gunicorn_options).run() + + except KeyboardInterrupt: + print("Server interrupted by user!!") + diff --git a/web_app/requirements.txt b/web_app/requirements.txt index 1780e15b..ac559b3d 100644 --- a/web_app/requirements.txt +++ b/web_app/requirements.txt @@ -1,28 +1,23 @@ bidict==0.22.1 blinker==1.6.3 -Bootstrap-Flask==2.3.2 -certifi==2023.7.22 -cffi==1.16.0;python_version>="3.8" -cffi==1.15.1;python_version<"3.8" +Bootstrap-Flask==2.4.0 +certifi==2024.2.2 +cffi==1.16.0 charset-normalizer==3.3.2 click==8.1.7 -cryptography==41.0.5 +cryptography==42.0.7 distro==1.8.0 -dnspython==2.4.2;python_version>="3.8" -dnspython==2.3.0;python_version<"3.8" -eventlet==0.33.3 -Flask==3.0.0;python_version>="3.8" -Flask==2.2.5;python_version<"3.8" +dnspython==2.6.1 +Flask==3.0.3 Flask-Login==0.6.3 Flask-SocketIO==5.3.6 -Flask-WTF==1.2.1;python_version>="3.8" -Flask-WTF==1.1.1;python_version<"3.8" -greenlet==3.0.1 +Flask-WTF==1.2.1 +gevent==24.2.1 +gunicorn==22.0.0 h11==0.14.0 -idna==3.4 -importlib-metadata==6.7.0;python_version<"3.8" +idna==3.7 itsdangerous==2.1.2 -Jinja2==3.1.2 +Jinja2==3.1.4 lxml==4.9.3 MarkupSafe==2.1.3 nmcli==1.3.0 @@ -30,19 +25,15 @@ pexpect==4.8.0 psutil==5.9.6 ptyprocess==0.7.0 pycparser==2.21 -pyOpenSSL==23.3.0 +pyOpenSSL==24.1.0 pyserial==3.5 pystemd==0.13.2 python-engineio==4.8.0 python-socketio==5.10.0 -requests==2.31.0 +requests==2.32.3 simple-websocket==1.0.0 six==1.16.0 -typing_extensions==4.7.1;python_version<"3.8" urllib3==2.0.7 -Werkzeug==3.0.1;python_version>="3.8" -Werkzeug==2.2.3;python_version<"3.8" +Werkzeug==3.0.3 wsproto==1.2.0 -WTForms==3.1.0;python_version>="3.8" -WTForms==3.0.1;python_version<"3.8" -zipp==3.15.0;python_version<"3.8" +WTForms==3.1.0 diff --git a/web_app/server.py b/web_app/server.py index 0b82d294..3dff915a 100755 --- a/web_app/server.py +++ b/web_app/server.py @@ -28,24 +28,20 @@ # You should have received a copy of the GNU General Public License # along with ReachView. If not, see . -#from gevent import monkey -#monkey.patch_all() -import eventlet -eventlet.monkey_patch() +from gevent import monkey +monkey.patch_all() import time import json import os import shutil -import signal import sys import requests import tempfile +import argparse from threading import Thread from RTKLIB import RTKLIB -from port import changeBaudrateTo115200 -from reach_tools import reach_tools, provisioner from ServiceController import ServiceController from RTKBaseConfigManager import RTKBaseConfigManager @@ -55,7 +51,6 @@ #import reach_bluetooth.bluetoothctl #import reach_bluetooth.tcp_bridge -from threading import Thread from flask_bootstrap import Bootstrap4 from flask import Flask, render_template, session, request, flash, url_for from flask import send_file, send_from_directory, redirect, abort @@ -73,7 +68,7 @@ from werkzeug.security import generate_password_hash from werkzeug.security import check_password_hash from werkzeug.utils import safe_join -import urllib +import gunicorn.app.base app = Flask(__name__) app.debug = False @@ -89,7 +84,7 @@ login=LoginManager(app) login.login_view = 'login_page' -socketio = SocketIO(app) +socketio = SocketIO(app, async_mode = 'gevent') bootstrap = Bootstrap4(app) #Get settings from settings.conf.default and settings.conf @@ -109,12 +104,28 @@ {"service_unit" : "str2str_file.service", "name" : "file"}, {'service_unit' : 'rtkbase_archive.timer', "name" : "archive_timer"}, {'service_unit' : 'rtkbase_archive.service', "name" : "archive_service"}, + {'service_unit' : 'rtkbase_raw2nmea.service', "name" : "raw2nmea"}, ] #Delay before rtkrcv will stop if no user is on status.html page rtkcv_standby_delay = 600 connected_clients = 0 +class StandaloneApplication(gunicorn.app.base.BaseApplication): + def __init__(self, app, options=None): + self.options = options or {} + self.application = app + super().__init__() + + def load_config(self): + config = {key: value for key, value in self.options.items() + if key in self.cfg.settings and value is not None} + for key, value in config.items(): + self.cfg.set(key.lower(), value) + + def load(self): + return self.application + class User(UserMixin): """ Class for user authentification """ def __init__(self, username): @@ -127,7 +138,7 @@ def check_password(self, password): class LoginForm(FlaskForm): """ Class for the loginform""" #username = StringField('Username', validators=[DataRequired()]) - password = PasswordField('Please enter the password:', validators=[DataRequired()]) + password = PasswordField('Please enter the RTKBase password:', validators=[DataRequired()]) remember_me = BooleanField('Remember Me') submit = SubmitField('Sign In') @@ -142,7 +153,7 @@ def update_password(config_object): if new_password != "": config_object.update_setting("general", "web_password_hash", generate_password_hash(new_password)) config_object.update_setting("general", "new_web_password", "") - + def manager(): """ This manager runs inside a separate thread It checks how long rtkrcv is running since the last user leaves the @@ -165,7 +176,7 @@ def manager(): if services_status != updated_services_status: services_status = updated_services_status socketio.emit("services status", json.dumps(services_status), namespace="/test") - print("service status", services_status) + #print("service status", services_status) volume_usage = get_volume_usage() sys_infos = {"cpu_temp" : cpu_temp, @@ -176,7 +187,7 @@ def manager(): "volume_total" : round(volume_usage.total / 10E8, 2), "volume_percent_used" : volume_usage.percent} socketio.emit("sys_informations", json.dumps(sys_infos), namespace="/test") - + if rtk.sleep_count > rtkcv_standby_delay and rtk.state != "inactive" or \ main_service.get("active") == False and rtk.state != "inactive": print("DEBUG Stopping rtkrcv") @@ -207,7 +218,7 @@ def repaint_services_button(services_list): service["btn_off_color"] = "outline-danger" elif service.get("state_ok") == True: service["btn_off_color"] = "outline-secondary" - + return services_list def old_get_cpu_temp(): @@ -243,7 +254,7 @@ def get_sbc_model(): Try to detect the single board computer used :return the model name or unknown if not detected """ - answer = subprocess.run(["cat", "/proc/device-tree/model"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE) + answer = subprocess.run(["cat", "/proc/device-tree/model"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=False) if answer.returncode == 0: sbc_model = answer.stdout.split("\n").pop().strip() else: @@ -251,7 +262,7 @@ def get_sbc_model(): return sbc_model @socketio.on("check update", namespace="/test") -def check_update(source_url = None, current_release = None, prerelease=rtkbaseconfig.getboolean("general", "prerelease"), emit = True): +def check_update(source_url = None, current_release = None, prerelease=rtkbaseconfig.getboolean("general", "prerelease"), return_emit = True): """ Check if a RTKBase update exists :param source_url: the url where we will try to find an update. It uses the github api. @@ -266,13 +277,12 @@ def check_update(source_url = None, current_release = None, prerelease=rtkbaseco # socketio.emit("new release", json.dumps(new_release), namespace="/test") #return new_release ## test - new_release = {} source_url = source_url if source_url is not None else "https://api.github.com/repos/stefal/rtkbase/releases" current_release = current_release if current_release is not None else rtkbaseconfig.get("general", "version").strip("v") current_release = current_release.split("-beta", 1)[0].split("-alpha", 1)[0].split("-rc", 1)[0].split("b", 1)[0] - - try: + + try: response = requests.get(source_url) response = response.json() for release in response: @@ -286,12 +296,12 @@ def check_update(source_url = None, current_release = None, prerelease=rtkbaseco new_release["url"] = asset.get("browser_download_url") break break - + except Exception as e: print("Check update error: ", e) new_release = { "error" : repr(e)} - - if emit: + + if return_emit: socketio.emit("new release", json.dumps(new_release), namespace="/test") return new_release @@ -307,7 +317,7 @@ def update_rtkbase(update_file=False): if not update_file: #Check if an update is available - update_url = check_update(emit=False).get("url") + update_url = check_update(return_emit=False).get("url") if update_url is None: return #Download update @@ -317,7 +327,7 @@ def update_rtkbase(update_file=False): update_file.save("/var/tmp/rtkbase_update.tar.gz") update_archive = "/var/tmp/rtkbase_update.tar.gz" print("update stored in /var/tmp/") - + if update_archive is None: socketio.emit("downloading_update", json.dumps({"result": 'false'}), namespace="/test") return @@ -335,24 +345,29 @@ def update_rtkbase(update_file=False): os.rmdir("/var/tmp/rtkbase") except FileNotFoundError: print("/var/tmp/rtkbase directory doesn't exist") - + #Extract archive tar.extractall("/var/tmp") source_path = os.path.join("/var/tmp/", primary_folder) - script_path = os.path.join(source_path, "rtkbase_update.sh") + script_path = os.path.join(source_path, "tools", "rtkbase_update.sh") + data_dir = app.config["DOWNLOAD_FOLDER"].split("/")[-1] current_release = rtkbaseconfig.get("general", "version").strip("v") standard_user = rtkbaseconfig.get("general", "user") #launch update verifications - answer = subprocess.run([script_path, source_path, rtkbase_path, app.config["DOWNLOAD_FOLDER"].split("/")[-1], current_release, standard_user, "--checking"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE) + answer = subprocess.run([script_path, source_path, rtkbase_path, data_dir, current_release, standard_user, "--checking"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=False) if answer.returncode != 0: socketio.emit("updating_rtkbase_stopped", json.dumps({"error" : answer.stderr.splitlines()}), namespace="/test") + print("Checking OS release failed. Update aborted!") else : #if ok, launch update script print("Launch update") socketio.emit("updating_rtkbase", namespace="/test") rtk.shutdownBase() time.sleep(1) - os.execl(script_path, "unused arg0", source_path, rtkbase_path, app.config["DOWNLOAD_FOLDER"].split("/")[-1], current_release, standard_user) + #update_service=ServiceController('rtkbase_update.service') + #update_service.start() + subprocess.Popen([script_path, source_path, rtkbase_path, data_dir, current_release, standard_user]) + #os.execl('/var/tmp/rtkbase_update.sh', "unused arg0", source_path, rtkbase_path, data_dir, current_release, standard_user) def download_update(update_path): update_archive = "/var/tmp/rtkbase_update.tar.gz" @@ -375,8 +390,8 @@ def inject_release(): g.sbc_model = get_sbc_model() @login.user_loader -def load_user(id): - return User(id) +def load_user(user_id): + return User(user_id) @app.route('/') @app.route('/index') @@ -390,27 +405,50 @@ def status_page(): base_coordinates = {"lat" : base_position[0], "lon" : base_position[1]} return render_template("status.html", base_coordinates = base_coordinates, tms_key = {"maptiler_key" : rtkbaseconfig.get("general", "maptiler_key")}) -@app.route('/settings') +@app.route('/settings', methods=['GET', 'POST']) @login_required def settings_page(): """ The settings page where you can manage the various services, the parameters, update, power... """ + # POST method when updating with a manual file + if request.method == 'POST': + uploaded_file = request.files['file'] + if uploaded_file.filename != '': + update_rtkbase(uploaded_file) + else: + print("wrong update file") + return ('', 204) + # variable needed when the gnss receiver offer a web interface + host_url = urllib.parse.urlparse(request.host_url) + gnss_rcv_url = urllib.parse.ParseResult(scheme=host_url.scheme, + netloc="{}:{}".format(host_url.hostname, rtkbaseconfig.get("main", "gnss_rcv_web_proxy_port")), + path=host_url.path, + params=host_url.params, query=host_url.query, + fragment=host_url.fragment) + #TODO use dict and not list main_settings = rtkbaseconfig.get_main_settings() + main_settings.append(gnss_rcv_url.geturl()) ntrip_A_settings = rtkbaseconfig.get_ntrip_A_settings() ntrip_B_settings = rtkbaseconfig.get_ntrip_B_settings() local_ntripc_settings = rtkbaseconfig.get_local_ntripc_settings() - file_settings = rtkbaseconfig.get_file_settings() rtcm_svr_settings = rtkbaseconfig.get_rtcm_svr_settings() + rtcm_client_settings = rtkbaseconfig.get_rtcm_client_settings() + rtcm_udp_svr_settings = rtkbaseconfig.get_rtcm_udp_svr_settings() + rtcm_udp_client_settings = rtkbaseconfig.get_rtcm_udp_client_settings() rtcm_serial_settings = rtkbaseconfig.get_rtcm_serial_settings() + file_settings = rtkbaseconfig.get_file_settings() return render_template("settings.html", main_settings = main_settings, ntrip_A_settings = ntrip_A_settings, ntrip_B_settings = ntrip_B_settings, local_ntripc_settings = local_ntripc_settings, - file_settings = file_settings, rtcm_svr_settings = rtcm_svr_settings, + rtcm_client_settings = rtcm_client_settings, + rtcm_udp_svr_settings = rtcm_udp_svr_settings, + rtcm_udp_client_settings = rtcm_udp_client_settings, rtcm_serial_settings = rtcm_serial_settings, + file_settings = file_settings, os_infos = distro.info(),) @app.route('/logs') @@ -441,14 +479,14 @@ def login_page(): password = loginform.password.data if not user.check_password(password): return abort(401) - + login_user(user, remember=loginform.remember_me.data) next_page = request.args.get('next') if not next_page or urllib.parse.urlsplit(next_page).netloc != '': next_page = url_for('status_page') return redirect(next_page) - + return render_template('login.html', title='Sign In', form=loginform) @app.route('/logout') @@ -468,10 +506,12 @@ def diagnostic(): for service in services_list + [rtkbase_web_service]: sysctl_status = subprocess.run(['systemctl', 'status', service['service_unit']], stdout=subprocess.PIPE, - universal_newlines=True) + universal_newlines=True, + check=False) journalctl = subprocess.run(['journalctl', '--since', '7 days ago', '-u', service['service_unit']], stdout=subprocess.PIPE, - universal_newlines=True) + universal_newlines=True, + check=False) #Replace carrier return to
for html view sysctl_status = sysctl_status.stdout.replace('\n', '
') @@ -480,28 +520,23 @@ def diagnostic(): logs.append({'name' : service['service_unit'], 'active' : active_state, 'sysctl_status' : sysctl_status, 'journalctl' : journalctl}) return render_template('diagnostic.html', logs = logs) - -@app.route('/manual_update', methods=['GET', 'POST']) -@login_required -def upload_file(): - if request.method == 'POST': - uploaded_file = request.files['file'] - if uploaded_file.filename != '': - update_rtkbase(uploaded_file) - return "Updating....please refresh in a few minutes" - return render_template('manual_update.html') + #### Handle connect/disconnect events #### @socketio.on("connect", namespace="/test") -def testConnect(): +def clientConnect(): global connected_clients connected_clients += 1 print("Browser client connected") + if rtkbaseconfig.get("general", "updated", fallback="False").lower() == "true": + rtkbaseconfig.remove_option("general", "updated") + rtkbaseconfig.write_file() + socketio.emit("update_successful", json.dumps({"result": 'true'}), namespace="/test") rtk.sendState() @socketio.on("disconnect", namespace="/test") -def testDisconnect(): +def clientDisconnect(): global connected_clients connected_clients -=1 print("Browser client disconnected") @@ -545,11 +580,11 @@ def startBase(): if rtk.get_rtkcv_option("inpstr1-format") != saved_input_type: rtk.set_rtkcv_option("inpstr1-format", saved_input_type) rtk.set_rtkcv_pending_refresh(True) - + if rtk.get_rtkcv_pending_status(): print("REFRESH NEEDED !!!!!!!!!!!!!!!!") rtk.startBase() - + @socketio.on("stop base", namespace="/test") def stopBase(): rtk.stopBase() @@ -558,12 +593,6 @@ def stopBase(): def continueBase(): rtk.sleep_count = 0 -#### Free space handler - -@socketio.on("get available space", namespace="/test") -def getAvailableSpace(): - rtk.socketio.emit("available space", reach_tools.getFreeSpace(path_to_gnss_log), namespace="/test") - #### Delete log button handler #### @socketio.on("delete log", namespace="/test") @@ -578,7 +607,7 @@ def deleteLog(json_msg): def detect_receiver(json_msg): print("Detecting gnss receiver") #print("DEBUG json_msg: ", json_msg) - answer = subprocess.run([os.path.join(rtkbase_path, "tools", "install.sh"), "--user", rtkbaseconfig.get("general", "user"), "--detect-gnss", "--no-write-port"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE) + answer = subprocess.run([os.path.join(rtkbase_path, "tools", "install.sh"), "--user", rtkbaseconfig.get("general", "user"), "--detect-gnss", "--no-write-port"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=False) if answer.returncode == 0 and "/dev/" in answer.stdout: #print("DEBUG ok stdout: ", answer.stdout) try: @@ -597,8 +626,8 @@ def detect_receiver(json_msg): socketio.emit("gnss_detection_result", json.dumps(result), namespace="/test") @socketio.on("configure_receiver", namespace="/test") -def configure_receiver(brand="u-blox", model="F9P"): - # only ZED-F9P could be configured automaticaly +def configure_receiver(brand="", model=""): + # only some receiver could be configured automaticaly # After port detection, the main service will be restarted, and it will take some time. But we have to stop it to # configure the receiver. We wait 2 seconds before stopping it to remove conflicting calls. time.sleep(4) @@ -610,7 +639,7 @@ def configure_receiver(brand="u-blox", model="F9P"): restart_main = False print("configuring {} gnss receiver model {}".format(brand, model)) - answer = subprocess.run([os.path.join(rtkbase_path, "tools", "install.sh"), "--user", rtkbaseconfig.get("general", "user"), "--configure-gnss"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE) + answer = subprocess.run([os.path.join(rtkbase_path, "tools", "install.sh"), "--user", rtkbaseconfig.get("general", "user"), "--configure-gnss"], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=False) #print("DEBUG - stdout: ", answer.stdout) #print("DEBUG - returncode: ", answer.returncode) @@ -631,7 +660,9 @@ def configure_receiver(brand="u-blox", model="F9P"): def reset_settings(): switchService({"name":"main", "active":False}) rtkbaseconfig.merge_default_and_user(os.path.join(rtkbase_path, "settings.conf.default"), os.path.join(rtkbase_path, "settings.conf.default")) + rtkbaseconfig.expand_path() rtkbaseconfig.write_file() + update_std_user(services_list) socketio.emit("settings_reset", namespace="/test") @app.route("/logs/download/settings") @@ -679,7 +710,7 @@ def rinex_ign(json_msg): convpath = os.path.abspath(os.path.join(rtkbase_path, "tools", "convbin.sh")) convbin_user = rtkbaseconfig.get("general", "user").strip("'") #print("DEBUG", convpath, json_msg.get("filename"), rtk.logm.log_path, rinex_type) - answer = subprocess.run(["sudo", "-u", convbin_user, convpath, json_msg.get("filename"), rtk.logm.log_path, rinex_type], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE) + answer = subprocess.run(["sudo", "-u", convbin_user, convpath, json_msg.get("filename"), rtk.logm.log_path, rinex_type], encoding="UTF-8", stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=False) if answer.returncode == 0 and "rinex_file=" in answer.stdout: rinex_file = answer.stdout.split("\n").pop().strip("rinex_file=") result = {"result" : "success", "file" : rinex_file} @@ -771,7 +802,7 @@ def restartServices(restart_services_list=None): """ Restart already running services This function will refresh all services status, then compare the global services_list and - the restart_services_list to find the services we need to restart. + then restart_services_list to find the services we need to restart. #TODO I don't really like this global services_list use. """ if restart_services_list == None: @@ -793,7 +824,7 @@ def restartServices(restart_services_list=None): service["unit"].start() else: service["unit"].restart() - + #refresh service status getServicesStatus() @@ -829,9 +860,9 @@ def getServicesStatus(emit_pingback=True): pass services_status = [] - for service in services_list: + for service in services_list: services_status.append({key:service[key] for key in service if key != 'unit'}) - + services_status = repaint_services_button(services_status) #print(services_status) if emit_pingback: @@ -892,7 +923,7 @@ def update_settings(json_msg): #Restart service if needed if source_section == "main": - restartServices(("main", "ntrip_A", "ntrip_B", "local_ntrip_caster", "rtcm_svr", "file", "rtcm_serial")) + restartServices(("main", "ntrip_A", "ntrip_B", "local_ntrip_caster", "rtcm_svr", "rtcm_client", "rtcm_udp_svr", "rtcm_udp_client", "file", "rtcm_serial", "raw2nmea")) elif source_section == "ntrip_A": restartServices(("ntrip_A",)) elif source_section == "ntrip_B": @@ -901,12 +932,41 @@ def update_settings(json_msg): restartServices(("local_ntrip_caster",)) elif source_section == "rtcm_svr": restartServices(("rtcm_svr",)) + elif source_section == "rtcm_client": + restartServices(("rtcm_client",)) + elif source_section == "rtcm_udp_svr": + restartServices(("rtcm_udp_svr",)) + elif source_section == "rtcm_udp_client": + restartServices(("rtcm_udp_client",)) elif source_section == "rtcm_serial": restartServices(("rtcm_serial",)) elif source_section == "local_storage": restartServices(("file",)) +def arg_parse(): + parser = argparse.ArgumentParser( + description="RTKBase Web server", + formatter_class=argparse.RawTextHelpFormatter, + ) + parser.add_argument( + "-d", + "--debug", + help="Enable web server debug mode", + action="store_true", + default=False, + ) + parser.add_argument( + "-p", + "--port", + type=int, + help="port used for the web server", + default=None + ) + args = parser.parse_args() + return args + if __name__ == "__main__": + args=arg_parse() try: #check if a new password is defined in settings.conf update_password(rtkbaseconfig) @@ -919,18 +979,22 @@ def update_settings(json_msg): services_list = load_units(services_list) #Update standard user in settings.conf update_std_user(services_list) - #check if we run RTKBase for the first time after an update - #and restart some services to let them send the new release number. - if rtkbaseconfig.get("general", "updated", fallback="False").lower() == "true": - restartServices(["ntrip_A", "ntrip_B", "local_ntrip_caster", "rtcm_svr", "rtcm_serial"]) - rtkbaseconfig.remove_option("general", "updated") - rtkbaseconfig.write_file() #Start a "manager" thread manager_thread = Thread(target=manager, daemon=True) manager_thread.start() app.secret_key = rtkbaseconfig.get_secret_key() - socketio.run(app, host = "::", port = rtkbaseconfig.get("general", "web_port", fallback=80)) # IPv6 "::" is mapped to IPv4 + #socketio.run(app, host = "::", port = args.port or rtkbaseconfig.get("general", "web_port", fallback=80), debug=args.debug) # IPv6 "::" is mapped to IPv4 + gunicorn_options = { + 'bind': ['%s:%s' % ('0.0.0.0', args.port or rtkbaseconfig.get("main", "web_port", fallback=80)), + '%s:%s' % ('[::1]', args.port or rtkbaseconfig.get("main", "web_port", fallback=80)) ], + 'workers': 1, + 'worker_class': 'gevent', + 'graceful_timeout': 10, + 'loglevel': 'debug' if args.debug else 'warning', + } + #start gunicorn + StandaloneApplication(app, gunicorn_options).run() except KeyboardInterrupt: print("Server interrupted by user!!") diff --git a/web_app/static/settings.js b/web_app/static/settings.js index dc59f1c4..c63e6e30 100644 --- a/web_app/static/settings.js +++ b/web_app/static/settings.js @@ -79,7 +79,7 @@ $(document).ready(function () { // View/hide password buttons for: Ntrip A, Ntrip B and Local caster document.querySelectorAll(".input-group-append").forEach(function(e) { var name = e.querySelector("button").id.replace("_button", ""); - if (!["svr_pwd_A", "svr_pwd_B", "local_ntripc_pwd"].includes(name)) + if (!["svr_pwd_A", "svr_pwd_B", "local_ntripc_pwd", "rtcm_client_pwd"].includes(name)) return; var button = $("#" + name + "_button"); @@ -228,7 +228,7 @@ $(document).ready(function () { socket.emit("services switch", {"name" : "local_ntrip_caster", "active" : switchStatus}); }) - // #################### RTCM server service Switch ######################### + // #################### RTCM TCP server service Switch ######################### var rtcmSvrSwitch = $('#rtcm_svr-switch'); // set the switch to on/off depending of the service status @@ -393,7 +393,7 @@ $(document).ready(function () { detectApplyBtnElt.setAttribute('data-dismiss', 'modal'); detectApplyBtnElt.innerText = "Close"; if (response['result'] === 'success') { - detectBodyElt.innerHTML = "GNSS receiver successfully configured. We will log out to refresh the settings"; + detectBodyElt.innerHTML = "GNSS receiver successfully configured!"; detectApplyBtnElt.removeAttribute('data-dismiss'); detectApplyBtnElt.onclick = function() { // window.location.reload(); @@ -444,9 +444,27 @@ $(document).ready(function () { $("#updateModal .modal-title").text("No Update available!"); $("#updateModal .modal-body").text("We're working on it. Come back later!"); $("#updateModal").modal(); - } - }) - + } + // check if url contains update=manual parameter to display the input form + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + if (urlParams.get('update') === 'manual' ) { + $("#updateModal .modal-body").append('

Manual Update:

'); + const upd_formElt = document.querySelector('#updateModal div.modal-body form'); + upd_formElt.addEventListener('submit', handleFileSubmit); + function handleFileSubmit(event) { + console.log('inside function handlefilesubmit'); + event.preventDefault; + fetch(upd_formElt.action, { + method: "post", + // body: new URLSearchParams(new FormData(form)) // for application/x-www-form-urlencoded + body: new FormData(upd_formElt) // for multipart/form-data + }); + $("#updateModal .modal-body").html(' Updating...'); + }; + } + }); + $("#start-update-button").on("click", function () { //$("#updateModal .modal-title").text(("Installing update")); socket.emit("update rtkbase"); @@ -484,9 +502,21 @@ $(document).ready(function () { socket.on("updating_rtkbase", function() { $("#updateModal .modal-body").text("Please wait...Updating..."); - update_countdown(600, 0); + //update_countdown(1200, 0); }) + socket.on("update_successful", function() { + console.log("update successful"); + $("#updateModal .modal-body").text("Update Successful!"); + $("#start-update-button").html('Refresh'); + $("#start-update-button").prop("disabled", false); + $("#start-update-button").off("click"); + $("#start-update-button").on("click", function() { + location.reload(); + }); + $("#updateModal").modal(); + }); + function update_countdown(remaining, count) { if(remaining === 0) location.reload(); diff --git a/web_app/templates/diagnostic.html b/web_app/templates/diagnostic.html index afd810ec..6c705f9a 100644 --- a/web_app/templates/diagnostic.html +++ b/web_app/templates/diagnostic.html @@ -15,8 +15,8 @@

- {{ service.sysctl_status|safe }}
- {{ service.journalctl|safe }}
+

STATUS:

{{ service.sysctl_status|safe }}

+

JOURNAL:

{{ service.journalctl|safe }}

{% endfor %} diff --git a/web_app/templates/manual_update.html b/web_app/templates/manual_update.html deleted file mode 100644 index 7252be95..00000000 --- a/web_app/templates/manual_update.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends 'base.html' %} - -{% block styles %} -{{super()}} - - -{% endblock %} - -{% block content %} -
-
-

Manual Update:

-
-

-

-
-
-
-
- -{% endblock %} - -{% block scripts %} -{{super()}} - -{% endblock %} \ No newline at end of file diff --git a/web_app/templates/proxy_base.html b/web_app/templates/proxy_base.html new file mode 100644 index 00000000..96a5c91f --- /dev/null +++ b/web_app/templates/proxy_base.html @@ -0,0 +1,35 @@ +{% from 'bootstrap4/nav.html' import render_nav_item %} + + + + {% block head %} + + + + + {% block styles %} + + + {% endblock %} + + {% endblock %} + + + + +
+ {% block content %}{% endblock %} +
+
+ + + + {% block scripts %} + + + + + + {% endblock %} + + diff --git a/web_app/templates/proxy_login.html b/web_app/templates/proxy_login.html new file mode 100644 index 00000000..1abab9f8 --- /dev/null +++ b/web_app/templates/proxy_login.html @@ -0,0 +1,7 @@ +{% extends 'proxy_base.html' %} +{% block content %} +
+ {% from 'bootstrap4/form.html' import render_form %} + {{ render_form(form) }} +
+{% endblock %} \ No newline at end of file diff --git a/web_app/templates/settings.html b/web_app/templates/settings.html index b6d96dc5..c8f257b0 100644 --- a/web_app/templates/settings.html +++ b/web_app/templates/settings.html @@ -2,6 +2,13 @@ {% block styles %} {{super()}} + {% endblock %} @@ -15,7 +22,7 @@

Services:

- + @@ -28,23 +35,23 @@

Services:

- -
Antenna's coordinates: latitude longitude elevation
+ + Antenna's coordinates: latitude (decimal degree) longitude (decimal degree) elevation (meter)
@@ -52,16 +59,16 @@

Services:

- -
Com port settings: baudrate:data bits:parity:stop bits:flow control
+ + Com port settings: baudrate:data bits:parity:stop bits:flow control
- -
Gnss receiver brand and model
+ + Gnss receiver brand and model
@@ -69,8 +76,8 @@

Services:

- -
Gnss receiver format (ubx,stq,rtcm3,tersus,...)
+ + Gnss receiver format (ubx,sbf,stq,rtcm3,tersus,...)
@@ -79,8 +86,8 @@

Services:

- -
Antenna information (model,serial number) - default value is NULLANTENNA
+ + ADVNULLANTENNA or information (model,serial number) for IGS calibrated antenna
@@ -89,8 +96,8 @@

Services:

- -
Local tcp port
+ + Local tcp port
@@ -106,7 +113,7 @@

Services:

- + @@ -118,22 +125,22 @@

Services:

- -
Caster url address
+ + Caster url address
- -
Caster port
+ + Caster port
- +
-
Caster password
+ Caster password
- -
Mount name
+ + Mount name
- -
Rtcm messages list
+ + Rtcm messages list: msg(interval in seconds),msg(interval in seconds),...
- -
Receiver dependent options
+ + Receiver dependent options, e.g. -TADJ=1 for U-Blox F9P
@@ -180,7 +187,7 @@

Services:

-
+ @@ -192,22 +199,22 @@

Services:

- -
Caster url address
+ + Caster url address
- -
Caster port
+ + Caster port
- +
-
Caster password
+ Caster password
- -
Mount name
+ + Mount name
- -
Rtcm messages list
+ + Rtcm messages list: msg(interval in seconds),msg(interval in seconds),...
- -
Receiver dependent options
+ + Receiver dependent options, e.g. -TADJ=1 for U-Blox F9P
@@ -254,27 +261,27 @@

Services:

-
+ - +
- -
Local Ntrip caster username for the rover
+ + Local Ntrip caster username you will use in your rover to connect
- +
-
Local Ntrip caster password for the rover
+ Local Ntrip caster password you will use in your rover to connect
- -
Local Ntrip Caster port number, e.g. 2101
+ + Local Ntrip Caster port number, e.g. 2101
- -
Local Ntrip caster mount name
+ + Local Ntrip caster mount name
- -
Local caster Rtcm messages list
+ + Local caster Rtcm messages list: msg(interval in seconds),msg(interval in seconds),...
- -
Local Ntrip Caster Receiver dependent options, e.g. -TADJ=1 for u-blox
+ + Receiver dependent options, e.g. -TADJ=1 for U-Blox F9P
@@ -322,13 +329,13 @@

Services:

- +
- + @@ -340,22 +347,22 @@

Services:

- -
Rtcm server port
+ + Rtcm server port
- -
Rtcm server messages list
+ + Rtcm messages list: msg(interval in seconds),msg(interval in seconds),...
- -
Receiver dependent options
+ + Receiver dependent options, e.g. -TADJ=1 for U-Blox F9P
@@ -370,7 +377,7 @@

Services:

-
+ @@ -382,29 +389,29 @@

Services:

- -
Serial output com port (without /dev/)
+ + Serial output com port (without /dev/)
- -
Serial output port settings
+ + Serial output port settings: 'baud rate':'data bits':'parity':'stop bits'
- -
Rtcm serial output messages list
+ + Rtcm messages list: msg(interval in seconds),msg(interval in seconds),...
- -
Receiver dependent options
+ + Receiver dependent options. ie: -TADJ=1 for U-Blox F9P
@@ -419,7 +426,7 @@

Services:

-
+ @@ -431,36 +438,36 @@

Services:

- -
Path to data directory
+ + Absolute path to the directory where the data will be stored
- -
File name construction (should start with %Y-%m-%d_%h-%M-%S)
+ + Data file name construction (should start with %Y-%m-%d_%h-%M-%S)
- +
- -
File rotation time (in hour)
+ + File rotation time (in hours)
- +
- -
File rotation time (in seconds)
+ + File overlap time (in seconds)
- -
Archive duration before deletion (in days)
+ + Archives older than this value (in days) will be deleted
@@ -520,7 +527,11 @@

System Settings:

Gnss receiver: