├── doc ├── .gitignore ├── xbistat.png ├── bistatic.pdf ├── BistaticHub.png ├── BlockDiagram.fig └── BlockDiagram.eps ├── NOTICE ├── vdefine.h ├── datanotice.hh ├── RcvrInfo.example ├── INSTALL ├── .gitignore ├── Makefile.am ├── configure.ac ├── CommandSender.hh ├── PhaseRelayer.hh ├── PB_BeamSource.hh ├── V_BeamSource.hh ├── ByteOrder.hh ├── NetReader.hh ├── DataType.hh ├── BeamSource.hh ├── DataType.cc ├── CommandSender.cc ├── PB_BeamSource.cc ├── mkinstalldirs ├── Receiver.hh ├── Beam.hh ├── V_BeamSource.cc ├── Beam.cc ├── README.md ├── LE_Unpack.hh ├── PhaseRelayer.cc ├── NetReader.cc ├── NCWriter.hh ├── LE_Unpack.cc ├── pb_fakesource.cc ├── VIRAQ_Beam.hh ├── PB_Beam.hh ├── install-sh ├── Receiver.cc ├── vb_fakesource.cc ├── MergedBeam.hh ├── missing ├── LICENSE ├── PB_Beam.cc ├── VIRAQ_Beam.cc ├── MergedBeam.cc ├── depcomp └── BistaticHub.py /doc/.gitignore: -------------------------------------------------------------------------------- 1 | *.lyx~ 2 | -------------------------------------------------------------------------------- /doc/xbistat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NCAR/BistaticHub/main/doc/xbistat.png -------------------------------------------------------------------------------- /doc/bistatic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NCAR/BistaticHub/main/doc/bistatic.pdf -------------------------------------------------------------------------------- /doc/BistaticHub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NCAR/BistaticHub/main/doc/BistaticHub.png -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright © The BistaticHub contributors 2 | Copyright © 1998 Binet, Inc. 3 | Copyright © 1998 University Corporation for Atmospheric Research 4 | -------------------------------------------------------------------------------- /vdefine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * vdefine.h 3 | * Placeholder header file, here only to make Mitch's globals.h happy! 4 | */ 5 | typedef void SCALE; /* bogus */ 6 | -------------------------------------------------------------------------------- /datanotice.hh: -------------------------------------------------------------------------------- 1 | // datanotice.hh 2 | // Just the port number for sending data notices to xbistat 3 | // 4 | // The notices themselves are just ASCII strings of the form: 5 | // 6 | // or 7 | // filename: 8 | // 9 | static const int XBDATANOTICE_PORT = 0x0bda; // "b"istatic "d"ata "a"vailable 10 | 11 | -------------------------------------------------------------------------------- /RcvrInfo.example: -------------------------------------------------------------------------------- 1 | # 2 | # Site name: quoted string 3 | # Format: VIRAQ or PIRAQ 4 | # Azimuth: degrees w.r.t. transmitting radar 5 | # Range: distance to transmitting radar in km 6 | # IP address: in dot notation 7 | # 8 | # Site Name Format Azimuth Range IP Address 9 | #======================================================= 10 | Radar VIRAQ 0.0 0.0 192.168.0.2 11 | Lichtenau PIRAQ 212.0 27.2 192.168.1.1 12 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions for 'BistaticHub' and Utilities 2 | ========================================================= 3 | 4 | If you don't have a Makefile in this directory, execute the following commands 5 | to generate it: 6 | 7 | $ aclocal 8 | $ autoconf 9 | $ automake 10 | $ ./configure 11 | 12 | Once you have a Makefile, generate the BistaticHub, pb_fakesource, and 13 | vb_fakesource programs by executing: 14 | 15 | $ make 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .deps 3 | aclocal.m4 4 | autom4te*.cache 5 | BistaticHub 6 | BistaticHub.log 7 | compile 8 | config.cache 9 | config.h 10 | config.h.in 11 | config.log 12 | config.status 13 | configure 14 | configure~ 15 | Makefile 16 | Makefile.in 17 | pb_fakesource 18 | RcvrInfo 19 | stamp-h1 20 | vb_fakesource 21 | 22 | # Ignore Eclipse-generated files 23 | .autotools 24 | .project 25 | .cproject 26 | .pydevproject 27 | .settings 28 | # end of Eclipse-generated files 29 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = BistaticHub pb_fakesource vb_fakesource 2 | 3 | BistaticHub_SOURCES = BistaticHub.cc Beam.cc CommandSender.cc \ 4 | DataType.cc LE_Unpack.cc MergedBeam.cc \ 5 | NCWriter.cc NetReader.cc PB_Beam.cc \ 6 | PB_BeamSource.cc PhaseRelayer.cc Receiver.cc VIRAQ_Beam.cc \ 7 | V_BeamSource.cc \ 8 | \ 9 | Beam.hh BeamSource.hh \ 10 | CommandSender.hh DataType.hh LE_Unpack.hh ByteOrder.hh \ 11 | MergedBeam.hh NCWriter.hh NetReader.hh PB_Beam.hh \ 12 | PB_BeamSource.hh PhaseRelayer.hh Receiver.hh \ 13 | VIRAQ_Beam.hh V_BeamSource.hh \ 14 | \ 15 | products.c globals.h vdefine.h 16 | 17 | pb_fakesource_SOURCES = pb_fakesource.cc LE_Unpack.cc 18 | 19 | vb_fakesource_SOURCES = vb_fakesource.cc LE_Unpack.cc 20 | 21 | EXTRA_DIST = BistaticHub.py 22 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.71]) 5 | AC_INIT([BistaticHub], [2.0], [BUG-REPORT-ADDRESS]) 6 | AM_INIT_AUTOMAKE([foreign -Wall]) 7 | AC_CONFIG_SRCDIR([BistaticHub.cc]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CXX 12 | AC_PROG_CC 13 | 14 | # Checks for libraries. 15 | AC_CHECK_LIB([netcdf], [nc_open]) 16 | 17 | # Checks for header files. 18 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h sys/socket.h sys/time.h sys/vfs.h unistd.h values.h]) 19 | 20 | # Checks for typedefs, structures, and compiler characteristics. 21 | AC_C_INLINE 22 | AC_TYPE_SIZE_T 23 | AC_CHECK_HEADER_STDBOOL 24 | 25 | # Checks for library functions. 26 | AC_FUNC_STRTOD 27 | AC_CHECK_FUNCS([alarm gettimeofday inet_ntoa memchr memmove memset mkdir pow select socket sqrt strchr strrchr]) 28 | 29 | AC_CONFIG_FILES([Makefile]) 30 | AC_OUTPUT 31 | -------------------------------------------------------------------------------- /CommandSender.hh: -------------------------------------------------------------------------------- 1 | // CommandSender.hh 2 | // Class to handle sending commands to bistatic receivers 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | // 21 | 22 | # ifndef _COMMAND_SENDER_HH_ 23 | # define _COMMAND_SENDER_HH_ 24 | 25 | class Receiver; 26 | 27 | class CommandSender 28 | { 29 | public: 30 | CommandSender( void ); 31 | void Send( const char *cmd, unsigned long ip_addr ); 32 | static const int ToAll = -1; 33 | private: 34 | int Socket; 35 | }; 36 | 37 | # endif // _COMMAND_SENDER_HH_ 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /PhaseRelayer.hh: -------------------------------------------------------------------------------- 1 | // PhaseRelayer.hh 2 | // Class to relay per-pulse phases from the radar to receivers 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // Copyright © 2000 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include "Receiver.hh" 22 | 23 | class PhaseRelayer 24 | { 25 | private: 26 | const ReceiverList_t* Rcvrs; 27 | int InFd; 28 | int OutFd; 29 | int InPort; 30 | int OutPort; 31 | 32 | public: 33 | PhaseRelayer( int in_port, int out_port, const ReceiverList_t* rcvrs ); 34 | inline int FD( void ) const { return InFd; } 35 | void ReadAndRelay( void ) const; 36 | void Relay( const void* packet, int len ) const; 37 | }; 38 | -------------------------------------------------------------------------------- /PB_BeamSource.hh: -------------------------------------------------------------------------------- 1 | // PB_BeamSource.hh 2 | // BeamSource implementation for PIRAQ-based systems 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # ifndef _PB_BEAMSOURCE_HH_ 22 | # define _PB_BEAMSOURCE_HH_ 23 | 24 | # include "BeamSource.hh" 25 | 26 | class Receiver; 27 | 28 | class PB_BeamSource : public BeamSource 29 | { 30 | public: 31 | PB_BeamSource( const Receiver* rcvr ); 32 | Beam *NextBeam( void ); 33 | int AcceptData( const char *data, int len ); 34 | private: 35 | static const int MaxBufLen = 32768; // max buffer len 36 | char Buffer[MaxBufLen]; // buffer for incoming data 37 | int BufLen; // how much are we actually using? 38 | const Receiver* Rcvr; 39 | }; 40 | 41 | # endif // _PB_BEAMSOURCE_HH_ 42 | -------------------------------------------------------------------------------- /V_BeamSource.hh: -------------------------------------------------------------------------------- 1 | // V_BeamSource.hh 2 | // BeamSource implementation for a VIRAQ-based bistatic receiver 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # ifndef _V_BEAMSOURCE_HH_ 22 | # define _V_BEAMSOURCE_HH_ 23 | 24 | # include "BeamSource.hh" 25 | 26 | class Receiver; 27 | 28 | class V_BeamSource : public BeamSource 29 | { 30 | public: 31 | V_BeamSource( const Receiver* rcvr ); 32 | Beam *NextBeam( void ); 33 | int AcceptData( const char *data, int len ); 34 | private: 35 | static const int MaxBufLen = 65536; // max buffer len 36 | char Buffer[MaxBufLen]; // buffer for incoming data 37 | int BufLen; // how much are we actually using? 38 | const Receiver* Rcvr; 39 | }; 40 | 41 | # endif // _V_BEAMSOURCE_HH_ 42 | -------------------------------------------------------------------------------- /ByteOrder.hh: -------------------------------------------------------------------------------- 1 | // ByteOrder.hh,v 1.1 2001/08/28 16:03:55 burghart Exp $ 2 | // Generic byte order function, returns either LittleEndian or BigEndian. 3 | // 4 | // Copyright © 2001 University Corporation for Atmospheric Research 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | # include 21 | # include 22 | # include 23 | # include 24 | 25 | typedef enum _ByteOrder 26 | { 27 | LittleEndian, BigEndian 28 | } ByteOrder; 29 | 30 | 31 | inline ByteOrder 32 | GetByteOrder(void) 33 | { 34 | char bytes[] = { 0, 1, 2, 3 }; 35 | uint32_t x = *(uint32_t*)bytes; 36 | 37 | switch (x) 38 | { 39 | case 0x03020100: 40 | return LittleEndian; 41 | case 0x00010203: 42 | return BigEndian; 43 | default: 44 | std::cerr << "Weird machine byte order 0x" << std::hex << std::setw(8) 45 | << std::setfill('0') << x << std::endl; 46 | exit( 1 ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /NetReader.hh: -------------------------------------------------------------------------------- 1 | // NetReader.hh 2 | // Network reader for monostatic radar data 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | 22 | # ifndef _NETREADER_HH_ 23 | # define _NETREADER_HH_ 24 | 25 | # include 26 | # include 27 | # include "Receiver.hh" 28 | 29 | // 30 | // type to map from IP addresses to the associated Receiver 31 | // 32 | typedef std::map ClientMap_t; 33 | 34 | 35 | 36 | class NetReader 37 | { 38 | public: 39 | NetReader( uint16_t socknum ); 40 | // register a client who's expecting data from the net 41 | int Register( Receiver *client ); 42 | // which file descriptor have we opened? 43 | inline int FD( void ) const { return Fd; } 44 | // read incoming data 45 | Receiver* Read( void ); 46 | private: 47 | int Socknum; 48 | int Fd; 49 | ClientMap_t ClientMap; 50 | }; 51 | 52 | # endif // _NETREADER_HH_ 53 | -------------------------------------------------------------------------------- /DataType.hh: -------------------------------------------------------------------------------- 1 | // DataType.hh 2 | // Enumerated type for bistatic data typing 3 | // 4 | // Copyright © 1998 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # ifndef _DATATYPE_HH_ 22 | # define _DATATYPE_HH_ 23 | 24 | #include 25 | #include 26 | 27 | // Data types we might return 28 | enum class DataType { 29 | DOUBLE, FLOAT, INT32, UINT16, INT16, UINT8, INT8 30 | }; 31 | 32 | // map from each of the data types above to its associated size in bytes 33 | static const std::map DataTypeLen { 34 | { DataType::DOUBLE, sizeof(double) }, 35 | { DataType::FLOAT, sizeof(float) }, 36 | { DataType::INT32, sizeof(long) }, 37 | { DataType::UINT16, sizeof(uint16_t) }, 38 | { DataType::INT16, sizeof(int16_t) }, 39 | { DataType::UINT8, sizeof(uint8_t) }, 40 | { DataType::INT8, sizeof(int8_t) } 41 | }; 42 | 43 | // Convert an array of one of our data types to an array of floats. 44 | void MakeFloatArray( const void *rawdata, DataType type, int step, 45 | float scale, float offset, float *fdata, int nvals ); 46 | 47 | # endif // _DATATYPE_HH_ 48 | -------------------------------------------------------------------------------- /BeamSource.hh: -------------------------------------------------------------------------------- 1 | // BeamSource.hh 2 | // BeamSource is used to construct and provide Beam-s of radar data from raw 3 | // radar data streams. 4 | // 5 | // Copyright © 1999 Binet Incorporated 6 | // Copyright © 1999 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | 23 | // BeamSource Interface: 24 | // 25 | // AcceptData( const char* data, int len ) 26 | // accept 'len' bytes of data, appending it to the data we 27 | // already have 28 | // 29 | // NextBeam( void ) 30 | // return a good beam if we have enough data to make one, 31 | // clearing any data used to build it from our buffer. 32 | // NextBeam() should set the LastDataTime member to time(0) 33 | // when a good beam is returned. 34 | // 35 | // 36 | # ifndef _BEAMSOURCE_HH_ 37 | # define _BEAMSOURCE_HH_ 38 | 39 | # include 40 | 41 | class Beam; 42 | 43 | class BeamSource 44 | { 45 | protected: 46 | time_t LastDataTime; 47 | public: 48 | virtual Beam *NextBeam( void ) = 0; 49 | virtual int AcceptData( const char *data, int len ) = 0; 50 | time_t TimeSinceLastData( void ) const 51 | { return( time( 0 ) - LastDataTime ); } 52 | }; 53 | 54 | # endif // _BEAMSOURCE_HH_ 55 | -------------------------------------------------------------------------------- /DataType.cc: -------------------------------------------------------------------------------- 1 | // DataType.cc 2 | // Enumerated type for bistatic data typing 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | # include "DataType.hh" 21 | # include "LE_Unpack.hh" 22 | 23 | void 24 | MakeFloatArray( const void *rawdata, DataType type, int step, float scale, 25 | float offset, float *fdata, int nvals ) 26 | /* 27 | * Unpack raw data of the given type into a floating point array. The step 28 | * tells the spacing in bytes between consecutive values to use from the 29 | * raw array. Conversion takes the form: floatval = rawval * scale + offset. 30 | */ 31 | { 32 | int i; 33 | 34 | for (i = 0; i < nvals; i++) 35 | { 36 | const char *c = (const char*) rawdata + i * step; 37 | 38 | switch (type) 39 | { 40 | case DataType::FLOAT: 41 | fdata[i] = LE_Float( c ).Value(); 42 | break; 43 | case DataType::INT32: 44 | fdata[i] = LE_Long( c ).Value(); 45 | break; 46 | case DataType::INT16: 47 | fdata[i] = LE_Short( c ).Value(); 48 | break; 49 | case DataType::UINT8: 50 | fdata[i] = LE_UChar( c ).Value(); 51 | break; 52 | case DataType::INT8: 53 | fdata[i] = LE_Char( c ).Value(); 54 | break; 55 | } 56 | fdata[i] *= scale; 57 | fdata[i] += offset; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /CommandSender.cc: -------------------------------------------------------------------------------- 1 | // CommandSender.cc 2 | // Class to handle sending commands to bistatic receivers 3 | // 4 | // Copyright © 1998 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include "CommandSender.hh" 29 | 30 | 31 | CommandSender::CommandSender( void ) 32 | { 33 | // 34 | // Open a UDP socket for sending commands to bistatic receivers 35 | // 36 | if ((Socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) 37 | { 38 | fprintf( stderr, "Error %d creating or configuring command socket\n", 39 | errno ); 40 | exit (1); 41 | } 42 | } 43 | 44 | 45 | void 46 | CommandSender::Send( const char *cmd, unsigned long ip_addr ) 47 | { 48 | struct sockaddr_in to; 49 | // 50 | // Set up the recipient's address using the given IP address (must be in 51 | // network order) and the bistatic command port 21001 52 | // 53 | memset( (char*)&to, 0, sizeof( to ) ); 54 | to.sin_family = AF_INET; 55 | to.sin_addr.s_addr = ip_addr; 56 | to.sin_port = htons (21001); 57 | // 58 | // Send the command 59 | // 60 | sendto( Socket, (void*)cmd, strlen( cmd ), 0, (struct sockaddr*)&to, 61 | sizeof( to ) ); 62 | } 63 | -------------------------------------------------------------------------------- /PB_BeamSource.cc: -------------------------------------------------------------------------------- 1 | // PB_BeamSource.cc 2 | // BeamSource implementation for PIRAQ-based systems 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include "PB_BeamSource.hh" 24 | # include "PB_Beam.hh" 25 | 26 | PB_BeamSource::PB_BeamSource( const Receiver* rcvr ) 27 | { 28 | LastDataTime = time( 0 ); 29 | BufLen = 0; 30 | Rcvr = rcvr; 31 | } 32 | 33 | 34 | Beam* 35 | PB_BeamSource::NextBeam( void ) 36 | // 37 | // Return a pointer to the next beam if we can generate a good one, otherwise 38 | // return 0. A good beam must be deleted by the caller. 39 | // 40 | { 41 | PB_Beam *beam = new PB_Beam( Buffer, BufLen, Rcvr ); 42 | 43 | if (beam->OK()) 44 | { 45 | LastDataTime = time (0); // using *our* clock, not the source's! 46 | return beam; 47 | } 48 | else 49 | { 50 | delete beam; 51 | return 0; 52 | } 53 | } 54 | 55 | 56 | int 57 | PB_BeamSource::AcceptData( const char *data, int len ) 58 | { 59 | // 60 | // We assume that we'll never get more than MaxBufLen at a time... 61 | // 62 | assert( len < MaxBufLen ); 63 | // 64 | // Make sure we have enough space to hold the incoming data 65 | // 66 | if ((len + BufLen) > MaxBufLen) 67 | { 68 | int diff = len + BufLen - MaxBufLen; 69 | memmove( Buffer, Buffer + diff, diff ); 70 | fprintf( stderr, "PB_BeamSource: dropped %d old bytes\n", diff ); 71 | BufLen -= diff; 72 | } 73 | // 74 | // Add the new data to the end of our buffer 75 | // 76 | memmove( Buffer + BufLen, data, len ); 77 | BufLen += len; 78 | 79 | return 1; 80 | } 81 | -------------------------------------------------------------------------------- /mkinstalldirs: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # mkinstalldirs --- make directory hierarchy 3 | # Author: Noah Friedman 4 | # Created: 1993-05-16 5 | # Public domain 6 | 7 | errstatus=0 8 | dirmode="" 9 | 10 | usage="\ 11 | Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." 12 | 13 | # process command line arguments 14 | while test $# -gt 0 ; do 15 | case "${1}" in 16 | -h | --help | --h* ) # -h for help 17 | echo "${usage}" 1>&2; exit 0 ;; 18 | -m ) # -m PERM arg 19 | shift 20 | test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } 21 | dirmode="${1}" 22 | shift ;; 23 | -- ) shift; break ;; # stop option processing 24 | -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option 25 | * ) break ;; # first non-opt arg 26 | esac 27 | done 28 | 29 | for file 30 | do 31 | if test -d "$file"; then 32 | shift 33 | else 34 | break 35 | fi 36 | done 37 | 38 | case $# in 39 | 0) exit 0 ;; 40 | esac 41 | 42 | case $dirmode in 43 | '') 44 | if mkdir -p -- . 2>/dev/null; then 45 | echo "mkdir -p -- $*" 46 | exec mkdir -p -- "$@" 47 | fi ;; 48 | *) 49 | if mkdir -m "$dirmode" -p -- . 2>/dev/null; then 50 | echo "mkdir -m $dirmode -p -- $*" 51 | exec mkdir -m "$dirmode" -p -- "$@" 52 | fi ;; 53 | esac 54 | 55 | for file 56 | do 57 | set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` 58 | shift 59 | 60 | pathcomp= 61 | for d 62 | do 63 | pathcomp="$pathcomp$d" 64 | case "$pathcomp" in 65 | -* ) pathcomp=./$pathcomp ;; 66 | esac 67 | 68 | if test ! -d "$pathcomp"; then 69 | echo "mkdir $pathcomp" 70 | 71 | mkdir "$pathcomp" || lasterr=$? 72 | 73 | if test ! -d "$pathcomp"; then 74 | errstatus=$lasterr 75 | else 76 | if test ! -z "$dirmode"; then 77 | echo "chmod $dirmode $pathcomp" 78 | 79 | lasterr="" 80 | chmod "$dirmode" "$pathcomp" || lasterr=$? 81 | 82 | if test ! -z "$lasterr"; then 83 | errstatus=$lasterr 84 | fi 85 | fi 86 | fi 87 | fi 88 | 89 | pathcomp="$pathcomp/" 90 | done 91 | done 92 | 93 | exit $errstatus 94 | 95 | # Local Variables: 96 | # mode: shell-script 97 | # sh-indentation: 3 98 | # End: 99 | # mkinstalldirs ends here 100 | -------------------------------------------------------------------------------- /Receiver.hh: -------------------------------------------------------------------------------- 1 | // Receiver.hh 2 | // Class to handle a bistatic receiver 3 | // 4 | // 5 | // Copyright © 1999 Binet Incorporated 6 | // Copyright © 1999 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # ifndef _RECEIVER_HH_ 23 | # define _RECEIVER_HH_ 24 | 25 | # include 26 | # include "BeamSource.hh" 27 | 28 | 29 | 30 | class NetReader; 31 | 32 | // 33 | // The incoming data formats we handle 34 | // 35 | typedef enum _BeamFormat 36 | { 37 | FmtPB, FmtVIRAQ 38 | } BeamFormat; 39 | 40 | 41 | 42 | class Receiver : public BeamSource 43 | { 44 | private: 45 | char *Sitename; /* Null terminated site name */ 46 | char Identifier; /* 1-character identifier for this receiver */ 47 | float Az; /* azimuth from xmitting radar, in degrees */ 48 | float Range; /* distance in km from xmitting radar */ 49 | BeamFormat Fmt; /* source format */ 50 | unsigned long IPAddr; /* rcvr's IP address (if any), in net order */ 51 | int Enabled; /* use this receiver? */ 52 | BeamSource *Src; 53 | int Count; /* how many beams so far? */ 54 | int DebugLvl; 55 | 56 | void ReportStatus( Beam* beam ); 57 | public: 58 | Receiver( const char* line, char id, NetReader *nr ); 59 | inline const char* Site( void ) const { return Sitename; } 60 | inline float AzFromRadar( void ) const { return Az; } 61 | inline float RangeFromRadar( void ) const { return Range; } 62 | inline unsigned long IP_Address( void ) const { return IPAddr; } 63 | void Disable( void ); 64 | void Enable( void ); 65 | inline int BeamCount( void ) { return Count; } 66 | inline int IsEnabled( void ) const { return Enabled; } 67 | Beam* NextBeam( void ); 68 | int AcceptData( const char* data, int len ); 69 | inline time_t TimeSinceLastData( void ) const 70 | { return Src->TimeSinceLastData(); } 71 | inline char Id( void ) { return Identifier; } 72 | void SetDebugLevel( int level ); 73 | }; 74 | 75 | // 76 | // Generic type for a vector of Receivers 77 | // 78 | typedef std::vector ReceiverList_t; 79 | 80 | # endif // _RECEIVER_HH_ 81 | -------------------------------------------------------------------------------- /Beam.hh: -------------------------------------------------------------------------------- 1 | // Beam.hh 2 | // Generic Beam class 3 | 4 | // Copyright © 2000 Binet, Inc. 5 | // Copyright © 2000 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | 22 | # ifndef _BEAM_HH_ 23 | # define _BEAM_HH_ 24 | 25 | # include "DataType.hh" 26 | 27 | class Receiver; 28 | 29 | // 30 | // Generic beam class (virtual) 31 | // 32 | 33 | class Beam 34 | { 35 | public: 36 | virtual ~Beam( void ) { } 37 | virtual int OK( void ) const = 0; 38 | virtual double Time( void ) const = 0; // seconds from 1 Jan 1970 00:00 UTC 39 | virtual int Gates( void ) const = 0; 40 | virtual float RcvrPulseWidth( void ) const = 0; // in seconds 41 | virtual float RangeToFirstGate( void ) const = 0; // m to center 42 | virtual float Azimuth( void ) const = 0; 43 | virtual float Elevation( void ) const = 0; 44 | virtual float FixedAngle( void ) const = 0; 45 | virtual float Frequency( void ) const = 0; 46 | virtual float PRT( void ) const = 0; 47 | virtual float Delay( void ) const = 0; 48 | virtual float RadarLat( void ) const = 0; 49 | virtual float RadarLon( void ) const = 0; 50 | virtual float RadarAlt( void ) const = 0; 51 | virtual int VolNum( void ) const = 0; 52 | virtual int SweepNum( void ) const = 0; 53 | virtual int Hits( void ) const = 0; 54 | virtual const char* ScanType( void ) const = 0; 55 | virtual const Receiver* Rcvr( void ) const = 0; 56 | virtual const char* Info( void ) const { return( "" ); } 57 | virtual const void* VelRaw( DataType *type, int *step, float *scale, 58 | float *offset ) const = 0; 59 | virtual const void* dBZRaw( DataType *type, int *step, float *scale, 60 | float *offset ) const = 0; 61 | virtual const void* dBmRaw( DataType *type, int *step, float *scale, 62 | float *offset ) const = 0; 63 | virtual const void* NCPRaw( DataType *type, int *step, float *scale, 64 | float *offset ) const = 0; 65 | virtual int VelData( float* data, int maxlen, float badval ) const; 66 | virtual int dBZData( float* data, int maxlen, float badval ) const; 67 | virtual int dBmData( float* data, int maxlen, float badval ) const; 68 | virtual int NCPData( float* data, int maxlen, float badval ) const; 69 | }; 70 | 71 | # endif // _BEAM_HH_ 72 | 73 | 74 | -------------------------------------------------------------------------------- /V_BeamSource.cc: -------------------------------------------------------------------------------- 1 | // V_BeamSource.cc 2 | // BeamSource implementation for a VIRAQ-based bistatic receiver 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1999 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include "V_BeamSource.hh" 24 | # include "VIRAQ_Beam.hh" 25 | 26 | V_BeamSource::V_BeamSource( const Receiver* rcvr ) 27 | { 28 | LastDataTime = time( 0 ); 29 | BufLen = 0; 30 | Rcvr = rcvr; 31 | } 32 | 33 | 34 | Beam* 35 | V_BeamSource::NextBeam( void ) 36 | // 37 | // Return a pointer to the next beam if we can generate a good one, otherwise 38 | // return 0. A good beam must be deleted by the caller. 39 | // 40 | { 41 | VIRAQ_Beam *beam = new VIRAQ_Beam( Buffer, BufLen, Rcvr ); 42 | 43 | if (beam->OK()) 44 | { 45 | LastDataTime = time( 0 ); // *our* time, not the source's 46 | return beam; 47 | } 48 | else 49 | { 50 | delete beam; 51 | return 0; 52 | } 53 | } 54 | 55 | 56 | int 57 | V_BeamSource::AcceptData( const char *data, int len ) 58 | { 59 | static long lastone = -1; 60 | long thisone; 61 | // 62 | // Strip off the packet header and verify that this packet is sequential 63 | // 64 | typedef struct _enHeader 65 | { 66 | short type; // first or continue 67 | long sequence; 68 | short frames_per_radial; 69 | short frame_num; 70 | } enHeader; 71 | 72 | const enHeader* hdr = (enHeader*) data; 73 | data += sizeof( enHeader ); 74 | len -= sizeof( enHeader ); 75 | 76 | thisone = hdr->sequence; 77 | if (lastone >= 0 && thisone != lastone + 1) 78 | { 79 | fprintf( stderr, 80 | "V_BeamSource: out-of-sequence packet (%d != %d+1)\n", 81 | thisone, lastone ); 82 | BufLen = 0; 83 | } 84 | // 85 | // We assume that we'll never get more than MaxBufLen at a time... 86 | // 87 | assert( len < MaxBufLen ); 88 | // 89 | // Make sure we have enough space to hold the incoming data 90 | // 91 | if ((len + BufLen) > MaxBufLen) 92 | { 93 | int diff = len + BufLen - MaxBufLen; 94 | memmove( Buffer, Buffer + diff, diff ); 95 | fprintf( stderr, "V_BeamSource: dropped %d old bytes\n", diff ); 96 | BufLen -= diff; 97 | } 98 | // 99 | // Add the new data to the end of our buffer 100 | // 101 | memmove( Buffer + BufLen, data, len ); 102 | BufLen += len; 103 | 104 | return 1; 105 | } 106 | -------------------------------------------------------------------------------- /Beam.cc: -------------------------------------------------------------------------------- 1 | // Beam.cc 2 | // generic Beam class 3 | // 4 | // Copyright © 1999 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include "Beam.hh" 23 | 24 | int 25 | Beam::VelData( float* data, int maxlen, float badval ) const 26 | { 27 | if (maxlen < Gates()) 28 | { 29 | fprintf( stderr, "Beam::VelData: not enough data space\n" ); 30 | return 0; 31 | } 32 | 33 | DataType type; 34 | int step; 35 | float scale, offset; 36 | const void *rawdata = VelRaw( &type, &step, &scale, &offset ); 37 | 38 | if (rawdata) 39 | MakeFloatArray( rawdata, type, step, scale, offset, data, Gates() ); 40 | else 41 | for (int i = 0; i < Gates(); i++) 42 | data[i] = badval; 43 | 44 | return( 1 ); 45 | } 46 | 47 | 48 | 49 | int 50 | Beam::dBZData( float* data, int maxlen, float badval ) const 51 | { 52 | if (maxlen < Gates()) 53 | { 54 | fprintf( stderr, "Beam::dBZData: not enough data space\n" ); 55 | return 0; 56 | } 57 | 58 | DataType type; 59 | int step; 60 | float scale, offset; 61 | const void *rawdata = dBZRaw( &type, &step, &scale, &offset ); 62 | 63 | if (rawdata) 64 | MakeFloatArray( rawdata, type, step, scale, offset, data, Gates() ); 65 | else 66 | for (int i = 0; i < Gates(); i++) 67 | data[i] = badval; 68 | 69 | return( 1 ); 70 | } 71 | 72 | 73 | 74 | int 75 | Beam::dBmData( float* data, int maxlen, float badval ) const 76 | { 77 | if (maxlen < Gates()) 78 | { 79 | fprintf( stderr, "Beam::dBmData: not enough data space\n" ); 80 | return 0; 81 | } 82 | 83 | DataType type; 84 | int step; 85 | float scale, offset; 86 | const void *rawdata = dBmRaw( &type, &step, &scale, &offset ); 87 | 88 | if (rawdata) 89 | MakeFloatArray( rawdata, type, step, scale, offset, data, Gates() ); 90 | else 91 | for (int i = 0; i < Gates(); i++) 92 | data[i] = badval; 93 | 94 | return( 1 ); 95 | } 96 | 97 | 98 | 99 | int 100 | Beam::NCPData( float* data, int maxlen, float badval ) const 101 | { 102 | if (maxlen < Gates()) 103 | { 104 | fprintf( stderr, "Beam::NCPData: not enough data space\n" ); 105 | return 0; 106 | } 107 | 108 | DataType type; 109 | int step; 110 | float scale, offset; 111 | const void *rawdata = NCPRaw( &type, &step, &scale, &offset ); 112 | 113 | if (rawdata) 114 | MakeFloatArray( rawdata, type, step, scale, offset, data, Gates() ); 115 | else 116 | for (int i = 0; i < Gates(); i++) 117 | data[i] = badval; 118 | 119 | return( 1 ); 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BistaticHub 2 | 3 | This repository contains the "hub" software for bistatic radar operations. 4 | Three programs live here: `BistaticHub`, `pb_fakesource`, and `vb_fakesource`. 5 | 6 | ## `BistaticHub` 7 | 8 | This is the operational hub software with the primary job 9 | of gathering data from the radar and the bistatic receivers, 10 | merging it, deriving winds, and writing data files. In 11 | addition, it will either forward phase information packets 12 | from the radar to the bistatic receivers (magnetron radar operation) 13 | or will generate beam information packets itself and send them 14 | to the bistatic receivers (S-Pol operation). Finally, it sends 15 | notices to the display program [xbistat](https://www.github.com/NCAR/xbistat) 16 | so that it knows when 17 | new beams are available. 18 | 19 | The program is in two pieces: `BistaticHub.py` and `BistaticHub`. The 20 | first is just a Python GUI wrapper for the second. 21 | 22 | ![xbistat](doc/BistaticHub.png?raw=true "BistaticHub.png") 23 | 24 | ## `pb_fakesource` 25 | 26 | This program simulates a bistatic receiver, generating "PIRAQ 27 | bistatic" beam data and sending it to the IP address given on 28 | the command line. For example, 29 | 30 | ```bash 31 | $ pb_fakesource 127.0.0.1 32 | ``` 33 | 34 | will send beams to 127.0.0.1. The beams generated will correspond 35 | in time to those generated by vb_fakesource. 36 | 37 | ## `vb_fakesource` 38 | 39 | This program simulates a transmitting radar, generating VIRAQ-style 40 | beams and sending them to the IP address given on the command 41 | line. The beams generated will correspond in time to those generated 42 | by pb_fakesource. 43 | 44 | 45 | ## Testing 46 | 47 | Here's a useful test set-up that can be run on a single machine; 48 | in this example the machine is 192.168.0.1. We take advantage 49 | of the fact that a machine on one network still has at least two 50 | usable IP addresses: the address on the attached net, and the 51 | loopback address 127.0.0.1. 52 | 53 | First, here's the `RcvrInfo` file: 54 | 55 | ``` 56 | # 57 | # Site name: string 58 | # Format: VIRAQ or PIRAQ 59 | # Azimuth: degrees w.r.t. transmitting radar 60 | # Range: distance to transmitting radar in km 61 | # IP address: in dot notation 62 | # 63 | # Site Name Format Azimuth Range IP Address 64 | #======================================================= 65 | Radar VIRAQ 0.0 0.0 192.168.0.1 66 | Bistatic1 PIRAQ 212.0 27.2 127.0.0.1 67 | ``` 68 | 69 | And to run the test using this file, we start up a fake source for 70 | both `Radar` and `Bistatic1`: 71 | 72 | ```bash 73 | $ vb_fakesource 192.168.0.1 & 74 | $ pb_fakesource 127.0.0.1 & 75 | ``` 76 | Note that the xx_fakesource programs take the *destination* IP 77 | address as a parameter, and the addresses in the RcvrInfo file 78 | are the expected *source* IP addresses. For our one-machine test, 79 | though, the source and destination IP addresses for each "receiver" 80 | are the same. 81 | 82 | Next, start up the hub software: 83 | 84 | ```bash 85 | $ BistaticHub.py -b & 86 | ``` 87 | 88 | Finally, you can start up a display if you wish: 89 | 90 | ```bash 91 | $ ../display/xbistat & 92 | ``` 93 | 94 | When you're finished, don't forget to kill the `pb_fakesource` and 95 | `vb_fakesource` instances. *Much* confusion can be generated if you 96 | try to run the test again and inadvertently have multiple copies 97 | of either of these programs sending data to the same IP address. 98 | -------------------------------------------------------------------------------- /doc/BlockDiagram.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 2 | Landscape 3 | Center 4 | Inches 5 | Letter 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 0 32 #808080 11 | 6 1800 1200 3600 2925 12 | 5 1 0 5 0 7 0 0 -1 0.000 1 1 0 0 1663.511 1802.013 1882 2840 2625 2250 2599 1302 13 | 1 3 0 1 0 32 1 0 20 0.000 1 0.0000 2638 2250 437 437 2638 2250 3075 2250 14 | 2 1 0 1 0 7 0 0 15 0.000 0 0 -1 0 0 2 15 | 3300 2250 3600 2250 16 | 2 1 0 4 0 0 0 0 5 0.000 0 1 -1 0 0 2 17 | 2625 2250 2175 2025 18 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 19 | 3000 1950 3300 1950 3300 2550 3000 2550 3000 1950 20 | 4 0 0 0 0 0 18 0.0000 0 195 585 2400 2925 radar\001 21 | -6 22 | 6 3600 1650 5625 2250 23 | 6 4275 1650 5625 2175 24 | 4 0 0 0 0 0 18 0.0000 0 195 1290 4275 1875 bistatic hub\001 25 | 4 0 0 0 0 0 18 0.0000 0 225 1065 4350 2100 computer\001 26 | -6 27 | 2 1 0 1 0 7 0 0 15 0.000 0 0 -1 0 0 2 28 | 3600 1950 3900 1950 29 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 30 | 3900 1650 4200 1650 4200 2250 3900 2250 3900 1650 31 | -6 32 | 6 4275 3675 6375 3975 33 | 5 1 0 4 32 0 0 0 -1 0.000 0 1 0 0 4800.000 3712.500 4650 3825 4800 3900 4950 3825 34 | 5 1 0 4 32 0 0 0 -1 0.000 0 1 0 0 6150.000 3712.500 6000 3825 6150 3900 6300 3825 35 | 5 1 0 4 32 0 0 0 -1 0.000 0 0 0 0 5850.000 3937.500 5700 3825 5850 3750 6000 3825 36 | 5 1 0 4 32 0 0 0 -1 0.000 0 0 0 0 4500.000 3937.500 4350 3825 4500 3750 4650 3825 37 | 4 0 32 0 0 0 18 0.0000 0 195 630 5025 3900 ISDN\001 38 | -6 39 | 6 6150 4050 6900 4500 40 | 4 0 0 0 0 0 18 0.0000 0 195 630 6150 4275 ISDN\001 41 | 4 0 0 0 0 0 18 0.0000 0 165 690 6150 4500 router\001 42 | -6 43 | 6 3900 4050 4650 4500 44 | 4 0 0 0 0 0 18 0.0000 0 195 630 3900 4275 ISDN\001 45 | 4 0 0 0 0 0 18 0.0000 0 165 690 3900 4500 router\001 46 | -6 47 | 2 2 0 1 0 0 0 0 20 0.000 0 0 7 0 0 5 48 | 3525 4800 3675 4800 3675 4950 3525 4950 3525 4800 49 | 2 2 0 1 0 0 0 0 20 0.000 0 0 -1 0 0 5 50 | 3525 1500 3675 1500 3675 1350 3525 1350 3525 1500 51 | 2 1 0 3 0 7 0 0 15 0.000 0 0 -1 0 0 2 52 | 3600 1500 3600 4800 53 | 2 1 1 2 32 0 0 0 -1 6.000 0 1 -1 0 0 5 54 | 8850 2700 9000 2700 9000 5100 4050 5100 4050 4950 55 | 2 1 1 2 32 0 0 0 -1 6.000 0 1 -1 0 0 5 56 | 8700 2550 8850 2550 8850 4950 3900 4950 3900 4800 57 | 2 2 1 2 32 0 0 0 -1 8.000 0 1 7 0 0 5 58 | 3825 2400 8700 2400 8700 4800 3825 4800 3825 2400 59 | 2 1 0 1 0 0 0 0 -1 0.000 0 0 -1 0 0 2 60 | 6900 4125 7200 4125 61 | 2 1 0 1 0 0 0 0 5 0.000 0 0 -1 0 0 2 62 | 6600 3825 6900 3825 63 | 2 1 0 3 0 0 0 0 5 0.000 0 0 -1 0 0 2 64 | 6900 3675 6900 4575 65 | 2 2 0 1 0 0 0 0 20 0.000 0 0 -1 0 0 5 66 | 6825 3675 6975 3675 6975 3525 6825 3525 6825 3675 67 | 2 2 0 1 0 0 0 0 20 0.000 0 0 -1 0 0 5 68 | 6825 4575 6975 4575 6975 4725 6825 4725 6825 4575 69 | 2 1 0 4 32 0 1 0 -1 0.000 0 1 -1 0 0 2 70 | 7350 3525 7350 3225 71 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 72 | 4050 3675 4350 3675 4350 3975 4050 3975 4050 3675 73 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 74 | 6300 3675 6600 3675 6600 3975 6300 3975 6300 3675 75 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 76 | 7200 3825 7500 3825 7500 4425 7200 4425 7200 3825 77 | 2 2 0 1 0 32 0 0 20 0.000 0 0 -1 0 0 5 78 | 7200 3525 7500 3525 7500 3825 7200 3825 7200 3525 79 | 2 3 0 4 0 32 0 0 20 0.000 1 1 -1 0 0 4 80 | 6575 2898 7345 3259 7704 2491 6575 2898 81 | 2 1 0 1 0 7 0 0 15 0.000 0 0 -1 0 0 2 82 | 3600 3825 4050 3825 83 | 4 0 0 0 0 0 18 0.0000 0 225 1035 7575 4140 receiver /\001 84 | 4 0 0 0 0 0 18 0.0000 0 195 1065 7575 4350 processor\001 85 | 4 0 0 0 0 0 18 0.0000 0 195 810 7650 3900 bistatic\001 86 | 4 0 32 0 0 0 18 0.0000 0 255 2190 3900 2625 per bistatic receiver\001 87 | -------------------------------------------------------------------------------- /LE_Unpack.hh: -------------------------------------------------------------------------------- 1 | // LE_Unpack.hh 2 | // Little-endian data classes which can have arbitrary byte alignments 3 | // 4 | // Copyright © 1998 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # ifndef _LE_UNPACK_HH_ 22 | # define _LE_UNPACK_HH_ 23 | 24 | # include 25 | 26 | class LE_Char 27 | { 28 | public: 29 | LE_Char( void ) {} 30 | LE_Char( char val ) { PutValue( val ); } 31 | LE_Char( const void *v ) { c = *(char*)v; } 32 | inline char Value( void ) const { return c; } 33 | inline void PutValue( char val ) { c = val; } 34 | private: 35 | char c; 36 | }; 37 | 38 | 39 | class LE_UChar 40 | { 41 | public: 42 | LE_UChar( void ) {} 43 | LE_UChar( unsigned char val ) { PutValue( val ); } 44 | LE_UChar( const void *v ) { c = *(unsigned char*)v; } 45 | inline unsigned char Value( void ) const { return c; } 46 | inline void PutValue( unsigned char val ) { c = val; } 47 | private: 48 | unsigned char c; 49 | }; 50 | 51 | 52 | class LE_Short 53 | { 54 | public: 55 | LE_Short( void ) {} 56 | LE_Short( short val ) { PutValue( val ); } 57 | LE_Short( const void *v ) { memmove( c, v, 2 ); } 58 | short Value( void ) const; 59 | void PutValue( short val ); 60 | private: 61 | char c[2]; 62 | }; 63 | 64 | 65 | class LE_UShort 66 | { 67 | public: 68 | LE_UShort( void ) {} 69 | LE_UShort( unsigned short val ) { PutValue( val ); } 70 | LE_UShort( const void *v ) { memmove( c, v, 2 ); } 71 | unsigned short Value( void ) const; 72 | void PutValue( unsigned short val ); 73 | private: 74 | char c[2]; 75 | }; 76 | 77 | 78 | class LE_Long 79 | { 80 | public: 81 | LE_Long( void ) {} 82 | LE_Long( long val ) { PutValue( val ); } 83 | LE_Long( const void *v ) { memmove( c, v, 4 ); } 84 | long Value( void ) const; 85 | void PutValue( long val ); 86 | private: 87 | char c[4]; 88 | }; 89 | 90 | 91 | class LE_ULong 92 | { 93 | public: 94 | LE_ULong( void ) {} 95 | LE_ULong( unsigned long val ) { PutValue( val ); } 96 | LE_ULong( const void *v ) { memmove( c, v, 4 ); } 97 | unsigned long Value( void ) const; 98 | void PutValue( unsigned long val ); 99 | private: 100 | char c[4]; 101 | }; 102 | 103 | 104 | class LE_Float 105 | { 106 | public: 107 | LE_Float( void ) {} 108 | LE_Float( float val ) { PutValue( val ); } 109 | LE_Float( const void *v ) { memmove( c, v, 4 ); } 110 | float Value( void ) const; 111 | void PutValue( float val ); 112 | private: 113 | char c[4]; 114 | }; 115 | 116 | 117 | class LE_Double 118 | { 119 | public: 120 | LE_Double( void ) {} 121 | LE_Double( double val ) { PutValue( val ); } 122 | LE_Double( const void *v ) { memmove( c, v, 8 ); } 123 | double Value( void ) const; 124 | void PutValue( double val ); 125 | private: 126 | char c[8]; 127 | }; 128 | 129 | # endif // _LE_UNPACK_HH_ 130 | -------------------------------------------------------------------------------- /PhaseRelayer.cc: -------------------------------------------------------------------------------- 1 | // PhaseRelayer.cc 2 | // Class to relay per-pulse phases from the radar to receivers 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // Copyright © 2000 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include "PhaseRelayer.hh" 29 | 30 | PhaseRelayer::PhaseRelayer( int in_port, int out_port, 31 | const ReceiverList_t* rcvrs ) 32 | { 33 | struct sockaddr_in saddr; 34 | 35 | InPort = htons( in_port ); // convert to network order 36 | OutPort = htons( out_port ); 37 | 38 | memset ((char*)&saddr, 0, sizeof( saddr )); 39 | saddr.sin_family = AF_INET; 40 | saddr.sin_addr.s_addr = INADDR_ANY; 41 | saddr.sin_port = InPort; 42 | 43 | if ((InFd = socket (AF_INET, SOCK_DGRAM, 0)) < 0 || 44 | bind (InFd, (struct sockaddr*)&saddr, sizeof (saddr))) 45 | { 46 | fprintf( stderr, "Error creating socket for incoming phases\n" ); 47 | exit( 1 ); 48 | } 49 | 50 | if ((OutFd = socket (AF_INET, SOCK_DGRAM, 0)) < 0 ) 51 | { 52 | fprintf( stderr, "Error creating socket for outgoing phases\n" ); 53 | exit( 1 ); 54 | } 55 | // 56 | // Keep hold of the receiver list 57 | // 58 | Rcvrs = rcvrs; 59 | } 60 | 61 | 62 | 63 | void 64 | PhaseRelayer::ReadAndRelay( void ) const 65 | // 66 | // Read a phase packet from our incoming socket and relay it to our 67 | // receivers. 68 | // 69 | { 70 | const int buflen = 1024; 71 | char buf[buflen]; 72 | // 73 | // Get the incoming phase data which should be waiting 74 | // 75 | struct sockaddr_in from; 76 | unsigned int fromlen = sizeof( struct sockaddr_in ); 77 | 78 | int nread = recvfrom( InFd, buf, buflen, 0, (struct sockaddr*)&from, 79 | &fromlen ); 80 | if (nread < 0) 81 | { 82 | fprintf( stderr, "Error %d reading phases from radar!\n", errno ); 83 | return; 84 | } 85 | // 86 | // Relay it 87 | // 88 | Relay( buf, nread ); 89 | } 90 | 91 | 92 | 93 | void 94 | PhaseRelayer::Relay( const void* packet, int len ) const 95 | { 96 | // 97 | // Now send the info to all but the transmitting radar (Rcvrs[0]) 98 | // 99 | for (int i = 1; i < Rcvrs->size(); i++) 100 | { 101 | if (! (*Rcvrs)[i]->IsEnabled()) 102 | continue; 103 | struct sockaddr_in to; 104 | 105 | memset( (char*)&to, 0, sizeof( to ) ); 106 | to.sin_family = AF_INET; 107 | to.sin_addr.s_addr = (*Rcvrs)[i]->IP_Address(); 108 | to.sin_port = OutPort; 109 | 110 | int nsent = sendto( OutFd, packet, len, 0, (struct sockaddr*)&to, 111 | sizeof( to ) ); 112 | 113 | if (nsent < 0) 114 | { 115 | if (errno != ECONNREFUSED) 116 | fprintf( stderr, "Error %d sending phases to %x\n", errno, 117 | (*Rcvrs)[i]->IP_Address() ); 118 | } 119 | else if (nsent < len) 120 | { 121 | fprintf( stderr, "Short phase write to %x (%d < %d)\n", 122 | (*Rcvrs)[i]->IP_Address(), nsent, len ); 123 | } 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /NetReader.cc: -------------------------------------------------------------------------------- 1 | // 2 | // NetReader.cc 3 | // Network reader for monostatic radar data 4 | // 5 | // Copyright © 1999 Binet Incorporated 6 | // Copyright © 1999 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include 29 | # include 30 | # include "NetReader.hh" 31 | # include "Receiver.hh" 32 | 33 | 34 | NetReader::NetReader( unsigned short snum ) 35 | // 36 | // Open a port for reading network data, using the given socket number 37 | // in local representation. 38 | // 39 | { 40 | Socknum = snum; 41 | // 42 | // Open a UDP socket for the given socket number 43 | // 44 | struct sockaddr_in saddr; 45 | 46 | memset ((char*)&saddr, 0, sizeof( saddr )); 47 | saddr.sin_family = AF_INET; 48 | saddr.sin_addr.s_addr = INADDR_ANY; 49 | saddr.sin_port = htons( Socknum ); 50 | 51 | if ((Fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0 || 52 | bind (Fd, (struct sockaddr*)&saddr, sizeof (saddr))) 53 | { 54 | fprintf( stderr, 55 | "NetReader %d: Error creating or configuring socket\n", 56 | Socknum ); 57 | exit( 1 ); // fatal (for now?) 58 | } 59 | } 60 | 61 | 62 | 63 | int 64 | NetReader::Register( Receiver* client ) 65 | // 66 | // Register a client to receive data from its Receiver's IP address 67 | // 68 | { 69 | unsigned int ip_addr = client->IP_Address(); 70 | // 71 | // Make sure we don't already have a client for this IP address 72 | // 73 | if (ClientMap[ip_addr]) 74 | { 75 | struct in_addr addr; 76 | addr.s_addr = ip_addr; 77 | fprintf( stderr, "NetReader %d: I already have a client for %s\n", 78 | Socknum, inet_ntoa( addr ) ); 79 | return 0; 80 | } 81 | // 82 | // Stash the client in our map 83 | // 84 | ClientMap[ip_addr] = client; 85 | return 1; 86 | } 87 | 88 | 89 | 90 | Receiver* 91 | NetReader::Read( void ) 92 | // 93 | // Read anything waiting on our socket and pass it along to the appropriate 94 | // client Receiver (if any), returning a pointer to the Receiver or NULL 95 | // 96 | { 97 | char buf[2048]; 98 | struct sockaddr_in from; 99 | unsigned int fromlen = sizeof( from ); 100 | 101 | int nread = recvfrom( Fd, buf, sizeof( buf ), 0, (struct sockaddr*) &from, 102 | &fromlen ); 103 | if (nread < 0) 104 | { 105 | fprintf( stderr, "NetReader %d: Error %d on data read\n", 106 | Socknum, errno ); 107 | return 0; 108 | } 109 | // 110 | // If we have a client associated with the source IP address, pass along 111 | // the new data. Otherwise, complain and return. 112 | // 113 | Receiver *client = ClientMap[from.sin_addr.s_addr]; 114 | 115 | if (! client) 116 | { 117 | fprintf( stderr, "NetReader %d: Unexpected data received from %s\n", 118 | Socknum, inet_ntoa( from.sin_addr ) ); 119 | return 0; 120 | } 121 | // 122 | // Pass the data on to our client 123 | // 124 | if (client->AcceptData( buf, nread )) 125 | return client; 126 | else 127 | return 0; 128 | } 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /NCWriter.hh: -------------------------------------------------------------------------------- 1 | // NCWriter.hh 2 | // BistaticHub netCDF writer class 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | # ifndef _NCWRITER_HH_ 21 | # define _NCWRITER_HH_ 22 | 23 | # include 24 | # include 25 | # include 26 | 27 | class MergedBeam; 28 | 29 | class NCWriter 30 | { 31 | public: 32 | NCWriter( const char* dir, int temponly = 0 ); 33 | ~NCWriter( void ); 34 | inline const char* FileName( void ) const { return FName; } 35 | int Write( const MergedBeam* mbeam ); 36 | inline int LastIndexOfFile( void ) const { return TimeIndex - 1; } 37 | private: 38 | char* BaseDir; 39 | char FName[256]; 40 | int TempOnly; 41 | int NumRcvrs; 42 | int NCid; 43 | int BaseTime; 44 | size_t TimeIndex; 45 | int MaxCells; 46 | // dimensions 47 | int TimeDim; 48 | int GateDim; 49 | int RcvrDim; 50 | // variables 51 | int AzVar; 52 | int ElVar; 53 | int TimeVar; 54 | int *ZVars; 55 | int *VelVars; 56 | int *NCPVars; 57 | int *UVars; 58 | int *VVars; 59 | int UBestVar; 60 | int VBestVar; 61 | // bookkeeping 62 | int CurrentVolume; 63 | int CurrentSweep; 64 | long Filesize; 65 | // general constants 66 | static constexpr float FBADVAL = -MAXFLOAT; 67 | static constexpr int16_t SBADVAL = MINSHORT; 68 | static constexpr float _C_ = 2.998e8; 69 | // constants for scaling float values to int16_ts 70 | static constexpr float PWRSCALE = 0.01; 71 | static constexpr float PWROFFSET = 0.0; 72 | static constexpr float VELSCALE = 0.01; 73 | static constexpr float VELOFFSET = 0.0; 74 | static constexpr float NCPSCALE = 0.01; 75 | static constexpr float NCPOFFSET = 0.0; 76 | // 77 | // Private methods 78 | // 79 | int StartNewFile( const MergedBeam *mb ); 80 | void CloseFile( void ); 81 | int DoDefinitions( const MergedBeam* mb ); 82 | void MakeFileName( const MergedBeam* mb ); 83 | void NCErrTest( int status ); 84 | int DefVar( const char* name, nc_type type, int ndims, const int* dims, 85 | const char* longname, const char* comment, const char* units, 86 | const void* validrange, const void* missingval, 87 | const void* fillval ); 88 | int DefShortVar( const char* name, int ndims, const int* dims, 89 | const char* longname, const char* comment, 90 | const char* units, const int16_t validrange[2], 91 | int16_t missingval, int16_t fillval, int system_index, 92 | float scale, float offset ); 93 | int DefIntVar( const char* name, int ndims, const int* dims, 94 | const char* longname, const char* comment, 95 | const char* units, const int validrange[2], 96 | int missingval, int fillval ); 97 | int DefFloatVar( const char* name, int ndims, const int* dims, 98 | const char* longname, const char* comment, 99 | const char* units, const float validrange[2], 100 | float missingval, float fillval ); 101 | int DefDoubleVar( const char* name, int ndims, const int* dims, 102 | const char* longname, const char* comment, 103 | const char* units, const double validrange[2], 104 | double missingval, double fillval ); 105 | void GlobalAttrs( const MergedBeam* mb ); 106 | }; 107 | 108 | # endif // _NCWRITER_HH_ 109 | 110 | -------------------------------------------------------------------------------- /LE_Unpack.cc: -------------------------------------------------------------------------------- 1 | // 2 | // LE_Unpack.cc 3 | // Little-endian data classes which can have arbitrary byte alignments 4 | // 5 | // Copyright © 1998 Binet Incorporated 6 | // Copyright © 1998 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # include 23 | # include "ByteOrder.hh" 24 | # include "LE_Unpack.hh" 25 | 26 | 27 | 28 | 29 | short 30 | LE_Short::Value( void ) const 31 | { 32 | short s; 33 | 34 | if (GetByteOrder() == LittleEndian) 35 | memmove( &s, c, 2 ); 36 | else 37 | { 38 | char *sc = (char*)&s; 39 | sc[0] = c[1]; sc[1] = c[0]; 40 | } 41 | 42 | return s; 43 | } 44 | 45 | 46 | void 47 | LE_Short::PutValue( short s ) 48 | { 49 | if (GetByteOrder() == LittleEndian) 50 | memmove( c, &s, 2 ); 51 | else 52 | { 53 | char *sc = (char*)&s; 54 | c[0] = sc[1]; c[1] = sc[0]; 55 | } 56 | } 57 | 58 | 59 | unsigned short 60 | LE_UShort::Value( void ) const 61 | { 62 | unsigned short s; 63 | 64 | if (GetByteOrder() == LittleEndian) 65 | memmove( &s, c, 2 ); 66 | else 67 | { 68 | char *sc = (char*)&s; 69 | sc[0] = c[1]; sc[1] = c[0]; 70 | } 71 | 72 | return s; 73 | } 74 | 75 | 76 | void 77 | LE_UShort::PutValue( unsigned short s ) 78 | { 79 | if (GetByteOrder() == LittleEndian) 80 | memmove( c, &s, 2 ); 81 | else 82 | { 83 | char *sc = (char*)&s; 84 | c[0] = sc[1]; c[1] = sc[0]; 85 | } 86 | } 87 | 88 | 89 | long 90 | LE_Long::Value( void ) const 91 | { 92 | long l; 93 | 94 | if (GetByteOrder() == LittleEndian) 95 | memmove( &l, c, 4 ); 96 | else 97 | { 98 | char *lc = (char*)&l; 99 | lc[0] = c[3]; lc[1] = c[2]; lc[2] = c[1]; lc[3] = c[0]; 100 | } 101 | 102 | return l; 103 | } 104 | 105 | 106 | void 107 | LE_Long::PutValue( long l ) 108 | { 109 | if (GetByteOrder() == LittleEndian) 110 | memmove( c, &l, 4 ); 111 | else 112 | { 113 | char *lc = (char*)&l; 114 | c[0] = lc[3]; c[1] = lc[2]; c[2] = lc[1]; c[3] = lc[0]; 115 | } 116 | } 117 | 118 | 119 | 120 | unsigned long 121 | LE_ULong::Value( void ) const 122 | { 123 | unsigned long l; 124 | 125 | if (GetByteOrder() == LittleEndian) 126 | memmove( &l, c, 4 ); 127 | else 128 | { 129 | char *lc = (char*)&l; 130 | lc[0] = c[3]; lc[1] = c[2]; lc[2] = c[1]; lc[3] = c[0]; 131 | } 132 | 133 | return l; 134 | } 135 | 136 | 137 | void 138 | LE_ULong::PutValue( unsigned long l ) 139 | { 140 | if (GetByteOrder() == LittleEndian) 141 | memmove( c, &l, 4 ); 142 | else 143 | { 144 | char *lc = (char*)&l; 145 | c[0] = lc[3]; c[1] = lc[2]; c[2] = lc[1]; c[3] = lc[0]; 146 | } 147 | } 148 | 149 | 150 | 151 | float 152 | LE_Float::Value( void ) const 153 | { 154 | float f; 155 | 156 | if (GetByteOrder() == LittleEndian) 157 | memmove( &f, c, 4 ); 158 | else 159 | { 160 | char *fc = (char*)&f; 161 | fc[0] = c[3]; fc[1] = c[2]; fc[2] = c[1]; fc[3] = c[0]; 162 | } 163 | 164 | return f; 165 | } 166 | 167 | 168 | void 169 | LE_Float::PutValue( float f ) 170 | { 171 | if (GetByteOrder() == LittleEndian) 172 | memmove( c, &f, 4 ); 173 | else 174 | { 175 | char *fc = (char*)&f; 176 | c[0] = fc[3]; c[1] = fc[2]; c[2] = fc[1]; c[3] = fc[0]; 177 | } 178 | } 179 | 180 | 181 | double 182 | LE_Double::Value( void ) const 183 | { 184 | double d; 185 | 186 | if (GetByteOrder() == LittleEndian) 187 | memmove( &d, c, 8 ); 188 | else 189 | { 190 | char *dc = (char*)&d; 191 | dc[0] = c[7]; dc[1] = c[6]; dc[2] = c[5]; dc[3] = c[4]; 192 | dc[4] = c[3]; dc[5] = c[2]; dc[6] = c[1]; dc[7] = c[0]; 193 | } 194 | 195 | return d; 196 | } 197 | -------------------------------------------------------------------------------- /pb_fakesource.cc: -------------------------------------------------------------------------------- 1 | // pb_fakesource.cc 2 | // Crude simulator for a PIRAQ-based bistatic receiver 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // Copyright © 2000 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include 29 | # include 30 | # include 31 | # include 32 | # include "PB_Beam.hh" 33 | 34 | // 35 | // Make sure that PRT*HITS divides evenly into 60 * 8000000 (This forces 36 | // a new beam to start at the top of each minute, and makes math 37 | // bearable below. Remember this is just a testing program anyway...) 38 | // 39 | const int PRT = 8000; // * 1/8 us 40 | const int HITS = 60; 41 | const int NGATES = 150; 42 | 43 | PB_Hdr Hdr; 44 | int Socket; 45 | struct sockaddr_in To; 46 | 47 | void nextbeam( int junk ); 48 | 49 | 50 | int main( int argc, char *argv[] ) 51 | { 52 | // 53 | // Sanity checks 54 | // 55 | if (argc != 2) 56 | { 57 | fprintf( stderr, "Usage: %s \n", argv[0] ); 58 | exit( 1 ); 59 | } 60 | 61 | assert ((60 * 8000000) % (PRT * HITS) == 0); 62 | // 63 | // Open our outgoing socket 64 | // 65 | if ((Socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) 66 | { 67 | fprintf( stderr, "Error %d creating or configuring command socket\n", 68 | errno ); 69 | exit (1); 70 | } 71 | // 72 | // Set up the recipient's address using the given IP address (must be in 73 | // network order) and the bistatic data port 0x6006 74 | // 75 | memset( (char*)&To, 0, sizeof( To ) ); 76 | To.sin_family = AF_INET; 77 | To.sin_port = htons( 0x6006 ); 78 | inet_aton( argv[1], &To.sin_addr ); 79 | // 80 | // Header stuff that will remain constant 81 | // 82 | strncpy( Hdr.cookie, "PRQ", 3 ); 83 | Hdr.version = (unsigned char)1; 84 | Hdr.azimuth = (unsigned short)0; 85 | Hdr.elevation = (unsigned short)0; 86 | Hdr.flag = (unsigned short)(0x20); 87 | Hdr.sync = (unsigned long)0; 88 | Hdr.qtr_firstgate = (unsigned char)0; 89 | Hdr.format = 1 << PBFld_V | 1 << PBFld_P_NCP; 90 | Hdr.ngates = NGATES; 91 | Hdr.hits = HITS - 1; 92 | Hdr.pulsewidth = 16; // 2 us 93 | Hdr.prt = PRT; 94 | Hdr.delay = (unsigned short)0; 95 | Hdr.cmd = (unsigned char)0; 96 | Hdr.trailer = 'X'; 97 | 98 | signal( SIGALRM, nextbeam ); 99 | 100 | struct itimerval itv; 101 | itv.it_interval.tv_sec = 0; 102 | itv.it_interval.tv_usec = (PRT * HITS) / 8; 103 | itv.it_value.tv_sec = 0; 104 | itv.it_value.tv_usec = 1; 105 | 106 | setitimer( ITIMER_REAL, &itv, 0 ); 107 | 108 | while (1) 109 | { 110 | pause(); 111 | } 112 | } 113 | 114 | 115 | void 116 | nextbeam( int junk ) 117 | { 118 | static char* vel_data = 0; 119 | static char* p_ncp_data = 0; 120 | 121 | if (! vel_data) 122 | { 123 | char val; 124 | 125 | vel_data = new char[NGATES]; 126 | val = 32; // -128 to 127 => -nyquist to +nyquist 127 | memset( vel_data, val, NGATES ); 128 | 129 | 130 | p_ncp_data = new char[NGATES]; 131 | val = 36; // 5-bit power + 3-bit NCP 132 | memset( p_ncp_data, val, NGATES ); 133 | } 134 | // 135 | // Get current time and figure out the beam number within this minute. 136 | // (The assertion in main guarantees that a new beam starts exactly at 137 | // the top of each minute) 138 | // 139 | struct timeval tv; 140 | gettimeofday( &tv, 0 ); 141 | unsigned long minute = tv.tv_sec / 60; 142 | unsigned long minutesec = tv.tv_sec % 60; 143 | 144 | double d_beamnum = (8e6 * minutesec + 8 * tv.tv_usec) / (PRT * HITS); 145 | unsigned long beamnum = (unsigned long)d_beamnum; 146 | // printf( "%ld\n", beamnum ); 147 | double beamtime = (double)(beamnum * PRT * HITS) / 8e6; 148 | unsigned long ibeamtime = (unsigned long) beamtime; 149 | // 150 | // Convert to the time needed in the header 151 | // 152 | Hdr.time = minute * 60 + ibeamtime; 153 | Hdr.subsec = (short)((beamtime - ibeamtime) * 10000); 154 | // 155 | // 8 4-bit gates of power (first four zero) 156 | // 157 | Hdr.power = random() & 0xffff; 158 | // 159 | // 8 4-bit gates of velocity 160 | // 161 | Hdr.velocity = random(); 162 | // 163 | // Send the header, then the data 164 | // 165 | if (sendto( Socket, (void*)&Hdr, PB_HdrLen, 0, (struct sockaddr*)&To, 166 | sizeof( To ) ) < 0 || 167 | sendto( Socket, (void*)vel_data, NGATES, 0, (struct sockaddr*)&To, 168 | sizeof( To ) ) < 0 || 169 | sendto( Socket, (void*)p_ncp_data, NGATES, 0, (struct sockaddr*)&To, 170 | sizeof( To ) ) < 0) 171 | if (errno != ECONNREFUSED) 172 | fprintf( stderr, "Error %d sending data\n", errno ); 173 | 174 | signal( SIGALRM, nextbeam ); 175 | } 176 | -------------------------------------------------------------------------------- /VIRAQ_Beam.hh: -------------------------------------------------------------------------------- 1 | // VIRAQ_Beam.hh 2 | // This is the form of the PIRAQ bistatic beam 3 | // 4 | // 5 | // Copyright © 1998 Binet Incorporated 6 | // Copyright © 1998 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # ifndef _VIRAQ_BEAM_HH_ 23 | # define _VIRAQ_BEAM_HH_ 24 | 25 | # include "Beam.hh" 26 | # include "LE_Unpack.hh" 27 | 28 | 29 | // VIRAQ beam header 30 | class VIRAQ_Hdr 31 | { 32 | public: 33 | VIRAQ_Hdr( void ) {} 34 | 35 | char desc[4]; // == 'DWEL' 36 | LE_Short recordlen; // header + data 37 | LE_Short gates; 38 | LE_Short hits; 39 | LE_Float rcvr_pulsewidth; 40 | LE_Float prt; 41 | LE_Float delay; // delay to first gate 42 | LE_Char clutterfilter; 43 | LE_Char timeseries; 44 | LE_Short tsgate; 45 | LE_Long time; // seconds since 1970 46 | LE_Short subsec; // fractional seconds (.1 mS) 47 | LE_Float az; 48 | LE_Float el; 49 | LE_Float radar_longitude; 50 | LE_Float radar_latitude; 51 | LE_Float radar_altitude; 52 | LE_Float ew_velocity; 53 | LE_Float ns_velocity; 54 | LE_Float vert_velocity; 55 | LE_UChar dataformat; // see VIRAQFormats enum above 56 | LE_Float prt2; 57 | LE_Float fxd_angle; 58 | LE_UChar scan_type; 59 | LE_UChar scan_num; // bumped by one for each new scan 60 | LE_UChar vol_num; // bumped by one for each new vol 61 | LE_Long ray_count; 62 | LE_Char transition; 63 | LE_Float hxmit_power; // on the fly hor power 64 | LE_Float vxmit_power; // on the fly ver power 65 | char spare[100]; 66 | }; 67 | 68 | const int VIRAQ_HdrLen = sizeof (VIRAQ_Hdr); 69 | 70 | // 71 | // Special once-per-volume or when-something-changes data structure 72 | // (derived from globals.h RADAR) 73 | // 74 | class VIRAQ_RHdr 75 | { 76 | public: 77 | VIRAQ_RHdr( void ) {} 78 | 79 | char desc[4]; // == 'RHDR' 80 | LE_Short recordlen; 81 | LE_Short rev; 82 | LE_Short year; 83 | char radar_name[8]; 84 | LE_Char polarization; // H or V 85 | LE_Float test_pulse_pwr; // TP power (referred to antenna flange) 86 | LE_Float test_pulse_frq; // test pulse frequency 87 | LE_Float frequency; // transmit frequency 88 | LE_Float peak_power; // typical xmit power (at antenna flange) 89 | LE_Float noise_figure; 90 | LE_Float noise_power; // for subtracting from data 91 | LE_Float receiver_gain; // gain from antenna flange to PIRAQ input 92 | LE_Float data_sys_sat; // PIRAQ input power required for full scale 93 | LE_Float antenna_gain; 94 | LE_Float horz_beam_width; 95 | LE_Float vert_beam_width; 96 | LE_Float xmit_pulsewidth;// transmitted pulse width 97 | LE_Float rconst; // radar constant 98 | LE_Float phaseoffset; // offset for phi dp 99 | LE_Float vreceiver_gain; // ver gain from antenna flange to VIRAQ 100 | LE_Float vtest_pulse_pwr;// ver TP power referred to antenna flange 101 | LE_Float vantenna_gain; 102 | LE_Float misc[6]; // 6 more misc floats 103 | char text[960]; 104 | }; 105 | 106 | const int VIRAQ_RHdrLen = sizeof (VIRAQ_RHdr); 107 | 108 | // 109 | // Finally, the VIRAQ_Beam class itself 110 | // 111 | 112 | class VIRAQ_Beam : public Beam 113 | { 114 | public: 115 | VIRAQ_Beam( char *buf, int& len, const Receiver* rcvr ); 116 | ~VIRAQ_Beam( void ) { delete[] data; delete[] productdata; } 117 | int OK( void ) const; 118 | double Time( void ) const; 119 | int Gates( void ) const; 120 | float RcvrPulseWidth( void ) const; 121 | // this is decreed to always be 150 m 122 | inline float RangeToFirstGate( void ) const { return 150.0; } 123 | float Azimuth( void ) const; 124 | float Elevation( void ) const; 125 | float FixedAngle( void ) const; 126 | float Frequency( void ) const; 127 | float PRT( void ) const; 128 | float Delay( void ) const; 129 | float RadarLat( void ) const; 130 | float RadarLon( void ) const; 131 | float RadarAlt( void ) const; 132 | int VolNum( void ) const; 133 | int Hits( void ) const; 134 | int SweepNum( void ) const; 135 | const char* ScanType( void ) const; 136 | inline const Receiver* Rcvr( void ) const { return MyReceiver; } 137 | const void* VelRaw( DataType *type, int *step, float *scale, 138 | float *offset ) const; 139 | const void* dBZRaw( DataType *type, int *step, float *scale, 140 | float *offset ) const; 141 | const void* dBmRaw( DataType *type, int *step, float *scale, 142 | float *offset ) const; 143 | const void* NCPRaw( DataType *type, int *step, float *scale, 144 | float *offset ) const; 145 | const void* XmtrInfoPacket( int* len ); 146 | private: 147 | VIRAQ_RHdr rhdr; 148 | VIRAQ_Hdr hdr; 149 | const Receiver* MyReceiver; 150 | char *data; 151 | float *productdata; 152 | 153 | void CalculateProducts( void ); 154 | }; 155 | 156 | # endif // _VIRAQ_BEAM_HH_ 157 | -------------------------------------------------------------------------------- /PB_Beam.hh: -------------------------------------------------------------------------------- 1 | // PB_Beam.hh 2 | // This is the form of the PIRAQ bistatic beam 3 | // 4 | // Copyright © 1998 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # ifndef _PB_BEAM_HH_ 22 | # define _PB_BEAM_HH_ 23 | 24 | # include 25 | # include 26 | # include "Beam.hh" 27 | # include "LE_Unpack.hh" // little-endian types 28 | 29 | class Receiver; 30 | 31 | // 32 | // The header structure 33 | // 34 | typedef struct _PB_Hdr 35 | { 36 | char cookie[3]; // == 'PRQ' 37 | LE_UChar version; // 1 or 2 38 | LE_ULong time; // Unix time stamp 39 | LE_UShort subsec; // 100 microsecond units 40 | LE_UShort azimuth; // radar azimuth, deg*(65536/360.0) 41 | LE_UShort elevation; // radar elev., deg*(65536/360.0) 42 | LE_UShort flag; 43 | LE_ULong sync; // 100 nanosecond units 44 | LE_UChar qtr_firstgate; // first gate / 4 45 | LE_UChar format; // data format 46 | LE_UShort ngates; 47 | LE_ULong power; // 1st 8 power gates, 1/2 byte each 48 | LE_ULong velocity; // 1st 8 vel gates, 1/2 byte each 49 | // For format version 1, 1 clock count = 1/8 microsecond 50 | // For format version 2, 1 clock count = 1/10 microsecond 51 | LE_UChar pulsewidth; // clock counts 52 | LE_UChar hits; // hits 53 | LE_UShort prt; // clock counts 54 | LE_UShort delay; // clock counts 55 | LE_UChar cmd; // command character 56 | LE_UChar trailer; // == 'X' 57 | } PB_Hdr; 58 | 59 | const int PB_HdrLen = sizeof (PB_Hdr); 60 | 61 | // 62 | // Bits in the format code tell us which fields are being sent. Here's 63 | // the table... 64 | // 65 | enum PBF_BitID // Bit ID's so that we can refer to each by a name 66 | { 67 | PBFld_V, PBFld_P, PBFld_NCP, PBFld_3, PBFld_4, PBFld_5, PBFld_6, 68 | PBFld_P_NCP 69 | }; 70 | 71 | static const struct _PBFormatInfo 72 | { 73 | std::string name; 74 | int bytes_per_gate; 75 | } PBFormatInfo[8] = 76 | { 77 | { "V", 1 }, /* 0 - 8 bit velocity */ 78 | { "P", 1 }, /* 1 - 8 bit power */ 79 | { "?", 0 }, /* 2 - 8 bit NCP */ 80 | { "?", 0 }, /* 3 - unused */ 81 | { "?", 0 }, /* 4 - unused */ 82 | { "?", 0 }, /* 5 - unused */ 83 | { "?", 0 }, /* 6 - unused */ 84 | { "P+NCP", 1 } /* 7 - 5 bit power + 3 bit NCP */ 85 | }; 86 | 87 | 88 | 89 | class PB_Beam : public Beam 90 | { 91 | public: 92 | PB_Beam( char* inbuf, int& inbuflen, const Receiver* rcvr ); 93 | ~PB_Beam( void ); 94 | // usable beam? 95 | int OK( void ) const; 96 | // beam time, seconds since 1-Jan-1970,00:00 UTC 97 | double Time( void ) const; 98 | // number of gates 99 | int Gates( void ) const; 100 | // receiver pulsewidth, seconds 101 | float RcvrPulseWidth( void ) const; 102 | // range to center of first gate, meters 103 | float RangeToFirstGate( void ) const; 104 | // beam azimuth, degrees clockwise from true north 105 | float Azimuth( void ) const; 106 | // beam elevation, degrees above horizontal 107 | float Elevation( void ) const; 108 | // beam fixed angle, degrees 109 | inline float FixedAngle( void ) const { return 0.0; } 110 | // transmitter frequency, Hz 111 | inline float Frequency( void ) const { return PB_Frequency; } 112 | // set transmitter frequency, Hz 113 | // (this applies to *all* PB_Beams) 114 | static inline void SetFrequency( float freq ) { PB_Frequency = freq; } 115 | // xmit pulse repetition time, seconds 116 | float PRT( void ) const; 117 | // number of hits 118 | int Hits( void ) const; 119 | // delay between xmit pulse and sample start, seconds 120 | float Delay( void ) const; 121 | // lat, long, & alt 122 | float RadarLat( void ) const { return -MAXFLOAT; } 123 | float RadarLon( void ) const { return -MAXFLOAT; } 124 | float RadarAlt( void ) const { return -MAXFLOAT; } 125 | // volume number 126 | inline int VolNum( void ) const { return 0; } 127 | // sweep number 128 | inline int SweepNum( void ) const { return 0; } 129 | // scan type (always unknown) 130 | inline const char* ScanType( void ) const { return "UNK"; } 131 | // get a format-specific information string 132 | const char *Info( void ) const; 133 | // power and velocity from the first eight gates, for sync verification 134 | void SyncData( int *pwr, int *vel ); 135 | // raw velocity data 136 | const void *VelRaw( DataType *type, int *step, float *scale, 137 | float *offset ) const; 138 | // raw reflectivity data 139 | const void *dBZRaw( DataType *type, int *step, float *scale, 140 | float *offset ) const; 141 | // raw power data 142 | const void *dBmRaw( DataType *type, int *step, float *scale, 143 | float *offset ) const; 144 | // NCP data 145 | const void *NCPRaw( DataType *type, int *step, float *scale, 146 | float *offset ) const; 147 | // Receiver 148 | inline const Receiver* Rcvr( void ) const { return MyReceiver; } 149 | 150 | private: 151 | // 152 | // transmitter frequency, Hz; this must be set before returned velocities 153 | // will be correct 154 | // 155 | static float PB_Frequency; 156 | // 157 | // simple beam structure: header + data 158 | // 159 | PB_Hdr Hdr; 160 | char* Data; 161 | // 162 | // pointer to our Receiver info 163 | // 164 | const Receiver *MyReceiver; 165 | // 166 | // Clock count time: 1/8 microsecond for format version 1 (old receivers), 167 | // and 1/10 microsecond for version 2 (newer receivers) 168 | // 169 | float ClockCountTime; 170 | // 171 | // If we unpack some packed data, we keep it around 172 | // 173 | char* UnpackedPwr; 174 | char* UnpackedNCP; 175 | 176 | int OffsetToField( PBF_BitID id ) const; 177 | void UnpackP_NCP(); 178 | }; 179 | 180 | # endif // _PB_BEAM_HH_ 181 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5 (mit/util/scripts/install.sh). 5 | # 6 | # Copyright 1991 by the Massachusetts Institute of Technology 7 | # 8 | # Permission to use, copy, modify, distribute, and sell this software and its 9 | # documentation for any purpose is hereby granted without fee, provided that 10 | # the above copyright notice appear in all copies and that both that 11 | # copyright notice and this permission notice appear in supporting 12 | # documentation, and that the name of M.I.T. not be used in advertising or 13 | # publicity pertaining to distribution of the software without specific, 14 | # written prior permission. M.I.T. makes no representations about the 15 | # suitability of this software for any purpose. It is provided "as is" 16 | # without express or implied warranty. 17 | # 18 | # Calling this script install-sh is preferred over install.sh, to prevent 19 | # `make' implicit rules from creating a file called install from it 20 | # when there is no Makefile. 21 | # 22 | # This script is compatible with the BSD install script, but was written 23 | # from scratch. It can only install one file at a time, a restriction 24 | # shared with many OS's install programs. 25 | 26 | 27 | # set DOITPROG to echo to test this script 28 | 29 | # Don't use :- since 4.3BSD and earlier shells don't like it. 30 | doit="${DOITPROG-}" 31 | 32 | 33 | # put in absolute paths if you don't have them in your path; or use env. vars. 34 | 35 | mvprog="${MVPROG-mv}" 36 | cpprog="${CPPROG-cp}" 37 | chmodprog="${CHMODPROG-chmod}" 38 | chownprog="${CHOWNPROG-chown}" 39 | chgrpprog="${CHGRPPROG-chgrp}" 40 | stripprog="${STRIPPROG-strip}" 41 | rmprog="${RMPROG-rm}" 42 | mkdirprog="${MKDIRPROG-mkdir}" 43 | 44 | transformbasename="" 45 | transform_arg="" 46 | instcmd="$mvprog" 47 | chmodcmd="$chmodprog 0755" 48 | chowncmd="" 49 | chgrpcmd="" 50 | stripcmd="" 51 | rmcmd="$rmprog -f" 52 | mvcmd="$mvprog" 53 | src="" 54 | dst="" 55 | dir_arg="" 56 | 57 | while [ x"$1" != x ]; do 58 | case $1 in 59 | -c) instcmd="$cpprog" 60 | shift 61 | continue;; 62 | 63 | -d) dir_arg=true 64 | shift 65 | continue;; 66 | 67 | -m) chmodcmd="$chmodprog $2" 68 | shift 69 | shift 70 | continue;; 71 | 72 | -o) chowncmd="$chownprog $2" 73 | shift 74 | shift 75 | continue;; 76 | 77 | -g) chgrpcmd="$chgrpprog $2" 78 | shift 79 | shift 80 | continue;; 81 | 82 | -s) stripcmd="$stripprog" 83 | shift 84 | continue;; 85 | 86 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 87 | shift 88 | continue;; 89 | 90 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 91 | shift 92 | continue;; 93 | 94 | *) if [ x"$src" = x ] 95 | then 96 | src=$1 97 | else 98 | # this colon is to work around a 386BSD /bin/sh bug 99 | : 100 | dst=$1 101 | fi 102 | shift 103 | continue;; 104 | esac 105 | done 106 | 107 | if [ x"$src" = x ] 108 | then 109 | echo "install: no input file specified" 110 | exit 1 111 | else 112 | : 113 | fi 114 | 115 | if [ x"$dir_arg" != x ]; then 116 | dst=$src 117 | src="" 118 | 119 | if [ -d $dst ]; then 120 | instcmd=: 121 | chmodcmd="" 122 | else 123 | instcmd=$mkdirprog 124 | fi 125 | else 126 | 127 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 128 | # might cause directories to be created, which would be especially bad 129 | # if $src (and thus $dsttmp) contains '*'. 130 | 131 | if [ -f "$src" ] || [ -d "$src" ] 132 | then 133 | : 134 | else 135 | echo "install: $src does not exist" 136 | exit 1 137 | fi 138 | 139 | if [ x"$dst" = x ] 140 | then 141 | echo "install: no destination specified" 142 | exit 1 143 | else 144 | : 145 | fi 146 | 147 | # If destination is a directory, append the input filename; if your system 148 | # does not like double slashes in filenames, you may need to add some logic 149 | 150 | if [ -d $dst ] 151 | then 152 | dst="$dst"/`basename $src` 153 | else 154 | : 155 | fi 156 | fi 157 | 158 | ## this sed command emulates the dirname command 159 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 160 | 161 | # Make sure that the destination directory exists. 162 | # this part is taken from Noah Friedman's mkinstalldirs script 163 | 164 | # Skip lots of stat calls in the usual case. 165 | if [ ! -d "$dstdir" ]; then 166 | defaultIFS=' 167 | ' 168 | IFS="${IFS-${defaultIFS}}" 169 | 170 | oIFS="${IFS}" 171 | # Some sh's can't handle IFS=/ for some reason. 172 | IFS='%' 173 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 174 | IFS="${oIFS}" 175 | 176 | pathcomp='' 177 | 178 | while [ $# -ne 0 ] ; do 179 | pathcomp="${pathcomp}${1}" 180 | shift 181 | 182 | if [ ! -d "${pathcomp}" ] ; 183 | then 184 | $mkdirprog "${pathcomp}" 185 | else 186 | : 187 | fi 188 | 189 | pathcomp="${pathcomp}/" 190 | done 191 | fi 192 | 193 | if [ x"$dir_arg" != x ] 194 | then 195 | $doit $instcmd $dst && 196 | 197 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && 198 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && 199 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && 200 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi 201 | else 202 | 203 | # If we're going to rename the final executable, determine the name now. 204 | 205 | if [ x"$transformarg" = x ] 206 | then 207 | dstfile=`basename $dst` 208 | else 209 | dstfile=`basename $dst $transformbasename | 210 | sed $transformarg`$transformbasename 211 | fi 212 | 213 | # don't allow the sed command to completely eliminate the filename 214 | 215 | if [ x"$dstfile" = x ] 216 | then 217 | dstfile=`basename $dst` 218 | else 219 | : 220 | fi 221 | 222 | # Make a temp file name in the proper directory. 223 | 224 | dsttmp=$dstdir/#inst.$$# 225 | 226 | # Move or copy the file name to the temp name 227 | 228 | $doit $instcmd $src $dsttmp && 229 | 230 | trap "rm -f ${dsttmp}" 0 && 231 | 232 | # and set any options; do chmod last to preserve setuid bits 233 | 234 | # If any of these fail, we abort the whole thing. If we want to 235 | # ignore errors from any of these, just make sure not to ignore 236 | # errors from the above "$doit $instcmd $src $dsttmp" command. 237 | 238 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && 239 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && 240 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && 241 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && 242 | 243 | # Now rename the file to the real destination. 244 | 245 | $doit $rmcmd -f $dstdir/$dstfile && 246 | $doit $mvcmd $dsttmp $dstdir/$dstfile 247 | 248 | fi && 249 | 250 | 251 | exit 0 252 | -------------------------------------------------------------------------------- /Receiver.cc: -------------------------------------------------------------------------------- 1 | // Receiver.cc 2 | // Class to handle a bistatic receiver 3 | // 4 | // 5 | // Copyright © 1999 Binet Incorporated 6 | // Copyright © 1999 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include "Receiver.hh" 28 | # include "Beam.hh" 29 | # include "PB_Beam.hh" 30 | # include "NetReader.hh" 31 | # include "PB_BeamSource.hh" 32 | # include "V_BeamSource.hh" 33 | 34 | 35 | 36 | 37 | Receiver::Receiver( const char *line, char id, NetReader* nr ) 38 | // 39 | // This constructor is for a Receiver which delivers its data via a 40 | // network socket, which is owned by the given NetReader. 41 | // 42 | { 43 | char site[80], fmtname[40], ipstring[24]; 44 | float az, range; 45 | // 46 | // Receiver definition line should contain exactly five elements: 47 | // site name: quoted string 48 | // format: VIRAQ or PIRAQ 49 | // azimuth: degrees w.r.t. transmitting radar 50 | // range: distance from transmitting radar in km 51 | // IP address: in dot notation 52 | // 53 | int nelems = sscanf( line, "%s%s%f%f%s", site, fmtname, &az, 54 | &range, ipstring ); 55 | if (nelems != 5) 56 | { 57 | fprintf( stderr, "Bad receiver line '%s'\n", line ); 58 | exit( 1 ); 59 | } 60 | // 61 | // Site name 62 | // 63 | Sitename = new char[strlen( site ) + 1]; 64 | strcpy( Sitename, site ); 65 | // 66 | // Translate the format name string to either FmtPB or FmtVIRAQ 67 | // 68 | if (! strcmp( fmtname, "PIRAQ" )) 69 | Fmt = FmtPB; 70 | else if (! strcmp( fmtname, "VIRAQ" )) 71 | Fmt = FmtVIRAQ; 72 | else 73 | { 74 | fprintf( stderr, "Unknown receiver data format '%s' for %s", 75 | fmtname, site ); 76 | exit( 1 ); 77 | } 78 | // 79 | // Save the az and range 80 | // 81 | Az = az; 82 | Range = range; 83 | // 84 | // Translate the IP address string to network order integer representation 85 | // 86 | struct in_addr addr; 87 | if (! inet_aton( ipstring, &addr )) 88 | { 89 | fprintf( stderr, "Bad IP address %s for %s\n", addr, site ); 90 | exit( 1 ); 91 | } 92 | 93 | IPAddr = addr.s_addr; 94 | // 95 | // Register with our NetReader 96 | // 97 | nr->Register( this ); 98 | // 99 | // A few initializations 100 | // 101 | Identifier = id; 102 | Count = 0; 103 | DebugLvl = 0; 104 | // 105 | // We're enabled to start with 106 | // 107 | Enable(); 108 | } 109 | 110 | 111 | 112 | void 113 | Receiver::Enable( void ) 114 | // 115 | // Enable - set up to accept incoming data 116 | // 117 | { 118 | // 119 | // If we're already enabled, just return 120 | // 121 | if (Enabled) 122 | return; 123 | // 124 | // Create our BeamSource object 125 | // 126 | switch (Fmt) 127 | { 128 | case FmtPB: 129 | Src = new PB_BeamSource( this ); 130 | break; 131 | case FmtVIRAQ: 132 | Src = new V_BeamSource( this ); 133 | break; 134 | default: 135 | fprintf( stderr, "Huh? Bad format %d in Receiver::Enable\n" ); 136 | exit( 1 ); 137 | } 138 | 139 | Enabled = 1; 140 | } 141 | 142 | 143 | 144 | void 145 | Receiver::Disable( void ) 146 | // 147 | // Disable - drop any incoming data 148 | // 149 | { 150 | // 151 | // Delete our BeamSource, so we get rid of any currently existing data 152 | // 153 | if (Src) 154 | delete Src; 155 | 156 | Src = 0; 157 | Enabled = 0; 158 | } 159 | 160 | 161 | 162 | int 163 | Receiver::AcceptData( const char* data, int len ) 164 | // 165 | // Pass incoming data on to our BeamSource, unless we're disabled 166 | // 167 | { 168 | if (! Enabled) 169 | return 1; 170 | // 171 | // Debugging info 172 | // 173 | if (DebugLvl > 1) 174 | { 175 | fprintf( stderr, "%c", Identifier ); 176 | fflush( stderr ); 177 | } 178 | 179 | return Src->AcceptData( data, len ); 180 | } 181 | 182 | 183 | Beam* 184 | Receiver::NextBeam( void ) 185 | // 186 | // Try to return the next beam from our source, incrementing our beam 187 | // count if we get a good one. 188 | // 189 | { 190 | Beam* beam; 191 | 192 | if (! Enabled || !(beam = Src->NextBeam())) 193 | return 0; 194 | // 195 | // Update the receiver info once in a while 196 | // 197 | Count++; 198 | if (! (Count % 10)) 199 | ReportStatus( beam ); 200 | // 201 | // Maybe print some information based on the debug level 202 | // 203 | switch (DebugLvl) 204 | { 205 | case 0: 206 | case 1: 207 | break; 208 | case 2: 209 | fprintf( stderr, "(%c)", Identifier ); 210 | fflush( stderr ); 211 | break; 212 | default: 213 | fprintf( stderr, 214 | "(%c) t: %.3lf pwidth: %.3e ng: %d prt: %.4e\n", 215 | Identifier, beam->Time(), beam->RcvrPulseWidth(), 216 | beam->Gates(), beam->PRT() ); 217 | } 218 | 219 | return beam; 220 | } 221 | 222 | 223 | 224 | void 225 | Receiver::ReportStatus( Beam *beam ) 226 | // 227 | // Print a status line as we want it to show up in a display 228 | // 229 | { 230 | char info[80]; 231 | // 232 | // Info string 233 | // 234 | time_t t = (time_t)(beam->Time()); 235 | 236 | strftime( info, sizeof( info ), "%Y.%m.%d %H:%M:%S", gmtime( &t ) ); 237 | if (Fmt == FmtPB) 238 | sprintf( info + strlen( info ), " %s", ((PB_Beam*)beam)->Info() ); 239 | 240 | printf( "status: %s %s\n", Sitename, info ); 241 | // 242 | // Sync info only for PB_Beam data right now 243 | // 244 | if (Fmt != FmtPB) 245 | return; 246 | // 247 | // Print power and velocity one-byte data for the first eight gates 248 | // 249 | int pwr[8], vel[8]; 250 | ((PB_Beam*)beam)->SyncData( pwr, vel ); 251 | 252 | printf( "syncinfo: %s ", Sitename ); 253 | printf( "p %02d %02d %02d %02d %02d %02d %02d %02d ", pwr[0], pwr[1], 254 | pwr[2], pwr[3], pwr[4], pwr[5], pwr[6], pwr[7] ); 255 | printf( "v %+d %+d %+d %+d %+d %+d %+d %+d\n", vel[0], vel[1], vel[2], 256 | vel[3], vel[4], vel[5], vel[6], vel[7] ); 257 | } 258 | 259 | 260 | 261 | void 262 | Receiver::SetDebugLevel( int level ) 263 | { 264 | DebugLvl = level; 265 | 266 | if (DebugLvl > 3) 267 | DebugLvl = 3; 268 | 269 | if (DebugLvl < 0) 270 | DebugLvl = 0; 271 | } 272 | -------------------------------------------------------------------------------- /doc/BlockDiagram.eps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-2.0 EPSF-2.0 2 | %%Title: BlockDiagram.eps 3 | %%Creator: fig2dev Version 3.2 Patchlevel 0-beta3 4 | %%CreationDate: Sat Oct 10 15:42:35 1998 5 | %%For: burghart@deneb.stellar (Chris Burghart) 6 | %%Orientation: Portrait 7 | %%BoundingBox: 0 0 432 233 8 | %%Pages: 0 9 | %%BeginSetup 10 | %%EndSetup 11 | %%Magnification: 1.0000 12 | %%EndComments 13 | /$F2psDict 200 dict def 14 | $F2psDict begin 15 | $F2psDict /mtrx matrix put 16 | /col-1 {0 setgray} bind def 17 | /col0 {0.000 0.000 0.000 srgb} bind def 18 | /col1 {0.000 0.000 1.000 srgb} bind def 19 | /col2 {0.000 1.000 0.000 srgb} bind def 20 | /col3 {0.000 1.000 1.000 srgb} bind def 21 | /col4 {1.000 0.000 0.000 srgb} bind def 22 | /col5 {1.000 0.000 1.000 srgb} bind def 23 | /col6 {1.000 1.000 0.000 srgb} bind def 24 | /col7 {1.000 1.000 1.000 srgb} bind def 25 | /col8 {0.000 0.000 0.560 srgb} bind def 26 | /col9 {0.000 0.000 0.690 srgb} bind def 27 | /col10 {0.000 0.000 0.820 srgb} bind def 28 | /col11 {0.530 0.810 1.000 srgb} bind def 29 | /col12 {0.000 0.560 0.000 srgb} bind def 30 | /col13 {0.000 0.690 0.000 srgb} bind def 31 | /col14 {0.000 0.820 0.000 srgb} bind def 32 | /col15 {0.000 0.560 0.560 srgb} bind def 33 | /col16 {0.000 0.690 0.690 srgb} bind def 34 | /col17 {0.000 0.820 0.820 srgb} bind def 35 | /col18 {0.560 0.000 0.000 srgb} bind def 36 | /col19 {0.690 0.000 0.000 srgb} bind def 37 | /col20 {0.820 0.000 0.000 srgb} bind def 38 | /col21 {0.560 0.000 0.560 srgb} bind def 39 | /col22 {0.690 0.000 0.690 srgb} bind def 40 | /col23 {0.820 0.000 0.820 srgb} bind def 41 | /col24 {0.500 0.190 0.000 srgb} bind def 42 | /col25 {0.630 0.250 0.000 srgb} bind def 43 | /col26 {0.750 0.380 0.000 srgb} bind def 44 | /col27 {1.000 0.500 0.500 srgb} bind def 45 | /col28 {1.000 0.630 0.630 srgb} bind def 46 | /col29 {1.000 0.750 0.750 srgb} bind def 47 | /col30 {1.000 0.880 0.880 srgb} bind def 48 | /col31 {1.000 0.840 0.000 srgb} bind def 49 | /col32 {0.502 0.502 0.502 srgb} bind def 50 | 51 | end 52 | save 53 | -110.0 308.0 translate 54 | 1 -1 scale 55 | 56 | /cp {closepath} bind def 57 | /ef {eofill} bind def 58 | /gr {grestore} bind def 59 | /gs {gsave} bind def 60 | /sa {save} bind def 61 | /rs {restore} bind def 62 | /l {lineto} bind def 63 | /m {moveto} bind def 64 | /rm {rmoveto} bind def 65 | /n {newpath} bind def 66 | /s {stroke} bind def 67 | /sh {show} bind def 68 | /slc {setlinecap} bind def 69 | /slj {setlinejoin} bind def 70 | /slw {setlinewidth} bind def 71 | /srgb {setrgbcolor} bind def 72 | /rot {rotate} bind def 73 | /sc {scale} bind def 74 | /sd {setdash} bind def 75 | /ff {findfont} bind def 76 | /sf {setfont} bind def 77 | /scf {scalefont} bind def 78 | /sw {stringwidth} bind def 79 | /tr {translate} bind def 80 | /tnt {dup dup currentrgbcolor 81 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 82 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add 83 | 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} 84 | bind def 85 | /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 86 | 4 -2 roll mul srgb} bind def 87 | /DrawEllipse { 88 | /endangle exch def 89 | /startangle exch def 90 | /yrad exch def 91 | /xrad exch def 92 | /y exch def 93 | /x exch def 94 | /savematrix mtrx currentmatrix def 95 | x y tr xrad yrad sc 0 0 1 startangle endangle arc 96 | closepath 97 | savematrix setmatrix 98 | } def 99 | 100 | /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def 101 | /$F2psEnd {$F2psEnteredState restore end} def 102 | %%EndProlog 103 | 104 | $F2psBegin 105 | 10 setmiterlimit 106 | n -1000 6122 m -1000 -1000 l 10022 -1000 l 10022 6122 l cp clip 107 | 0.06000 0.06000 sc 108 | 7.500 slw 109 | % Ellipse 110 | n 2638 2250 437 437 0 360 DrawEllipse gs col32 1.00 shd ef gr gs col0 s gr 111 | 112 | % Polyline 113 | 1 slc 114 | 45.000 slw 115 | n 7350 3525 m 7350 3225 l gs col32 s gr 116 | % Arc 117 | 60.000 slw 118 | gs n 1663.5 1802.0 1060.7 78.1 -28.1 arcn 119 | gs col0 s gr 120 | gr 121 | 122 | % Polyline 123 | 0 slc 124 | 7.500 slw 125 | n 3300 2250 m 3600 2250 l gs col7 0.75 shd ef gr gs col0 s gr 126 | % Polyline 127 | 1 slc 128 | 45.000 slw 129 | n 2625 2250 m 2175 2025 l gs 0.75 setgray ef gr gs col0 s gr 130 | % Polyline 131 | 0 slc 132 | 7.500 slw 133 | n 3000 1950 m 3300 1950 l 3300 2550 l 3000 2550 l cp gs col32 1.00 shd ef gr gs col0 s gr 134 | /Times-Roman ff 270.00 scf sf 135 | 2400 2925 m 136 | gs 1 -1 sc (radar) col0 sh gr 137 | /Times-Roman ff 270.00 scf sf 138 | 4275 1875 m 139 | gs 1 -1 sc (bistatic hub) col0 sh gr 140 | /Times-Roman ff 270.00 scf sf 141 | 4350 2100 m 142 | gs 1 -1 sc (computer) col0 sh gr 143 | % Polyline 144 | n 3600 1950 m 3900 1950 l gs col7 0.75 shd ef gr gs col0 s gr 145 | % Polyline 146 | n 3900 1650 m 4200 1650 l 4200 2250 l 3900 2250 l cp gs col32 1.00 shd ef gr gs col0 s gr 147 | % Arc 148 | 45.000 slw 149 | gs n 4800.0 3712.5 187.5 143.1 36.9 arcn 150 | gs col32 s gr 151 | gr 152 | 153 | % Arc 154 | gs n 6150.0 3712.5 187.5 143.1 36.9 arcn 155 | gs col32 s gr 156 | gr 157 | 158 | % Arc 159 | gs n 5850.0 3937.5 187.5 -143.1 -36.9 arc 160 | gs col32 s gr 161 | gr 162 | 163 | % Arc 164 | gs n 4500.0 3937.5 187.5 -143.1 -36.9 arc 165 | gs col32 s gr 166 | gr 167 | 168 | /Times-Roman ff 270.00 scf sf 169 | 5025 3900 m 170 | gs 1 -1 sc (ISDN) col32 sh gr 171 | /Times-Roman ff 270.00 scf sf 172 | 6150 4275 m 173 | gs 1 -1 sc (ISDN) col0 sh gr 174 | /Times-Roman ff 270.00 scf sf 175 | 6150 4500 m 176 | gs 1 -1 sc (router) col0 sh gr 177 | /Times-Roman ff 270.00 scf sf 178 | 3900 4275 m 179 | gs 1 -1 sc (ISDN) col0 sh gr 180 | /Times-Roman ff 270.00 scf sf 181 | 3900 4500 m 182 | gs 1 -1 sc (router) col0 sh gr 183 | % Polyline 184 | 7.500 slw 185 | n 3525 4800 m 3675 4800 l 3675 4950 l 3525 4950 l cp gs 0.00 setgray ef gr gs col0 s gr 186 | % Polyline 187 | n 3525 1500 m 3675 1500 l 3675 1350 l 3525 1350 l cp gs 0.00 setgray ef gr gs col0 s gr 188 | % Polyline 189 | 30.000 slw 190 | n 3600 1500 m 3600 4800 l gs col7 0.75 shd ef gr gs col0 s gr 191 | % Polyline 192 | 1 slc 193 | 15.000 slw 194 | [90] 0 sd 195 | n 8850 2700 m 9000 2700 l 9000 5100 l 4050 5100 l 4050 4950 l gs col32 s gr [] 0 sd 196 | % Polyline 197 | [90] 0 sd 198 | n 8700 2550 m 8850 2550 l 8850 4950 l 3900 4950 l 3900 4800 l gs col32 s gr [] 0 sd 199 | % Polyline 200 | [120] 0 sd 201 | n 3825 2400 m 8700 2400 l 8700 4800 l 3825 4800 l cp gs col32 s gr [] 0 sd 202 | % Polyline 203 | 0 slc 204 | 7.500 slw 205 | n 6900 4125 m 7200 4125 l gs col0 s gr 206 | % Polyline 207 | n 6600 3825 m 6900 3825 l gs 0.75 setgray ef gr gs col0 s gr 208 | % Polyline 209 | 30.000 slw 210 | n 6900 3675 m 6900 4575 l gs 0.75 setgray ef gr gs col0 s gr 211 | % Polyline 212 | 7.500 slw 213 | n 6825 3675 m 6975 3675 l 6975 3525 l 6825 3525 l cp gs 0.00 setgray ef gr gs col0 s gr 214 | % Polyline 215 | n 6825 4575 m 6975 4575 l 6975 4725 l 6825 4725 l cp gs 0.00 setgray ef gr gs col0 s gr 216 | % Polyline 217 | n 4050 3675 m 4350 3675 l 4350 3975 l 4050 3975 l cp gs col32 1.00 shd ef gr gs col0 s gr 218 | % Polyline 219 | n 6300 3675 m 6600 3675 l 6600 3975 l 6300 3975 l cp gs col32 1.00 shd ef gr gs col0 s gr 220 | % Polyline 221 | n 7200 3825 m 7500 3825 l 7500 4425 l 7200 4425 l cp gs col32 1.00 shd ef gr gs col0 s gr 222 | % Polyline 223 | n 7200 3525 m 7500 3525 l 7500 3825 l 7200 3825 l cp gs col32 1.00 shd ef gr gs col0 s gr 224 | % Polyline 225 | 1 slj 226 | 1 slc 227 | 45.000 slw 228 | n 6575 2898 m 7345 3259 l 7704 2491 l cp gs col32 1.00 shd ef gr gs col0 s gr 229 | % Polyline 230 | 0 slj 231 | 0 slc 232 | 7.500 slw 233 | n 3600 3825 m 4050 3825 l gs col7 0.75 shd ef gr gs col0 s gr 234 | /Times-Roman ff 270.00 scf sf 235 | 7575 4140 m 236 | gs 1 -1 sc (receiver /) col0 sh gr 237 | /Times-Roman ff 270.00 scf sf 238 | 7575 4350 m 239 | gs 1 -1 sc (processor) col0 sh gr 240 | /Times-Roman ff 270.00 scf sf 241 | 7650 3900 m 242 | gs 1 -1 sc (bistatic) col0 sh gr 243 | /Times-Roman ff 270.00 scf sf 244 | 3900 2625 m 245 | gs 1 -1 sc (per bistatic receiver) col32 sh gr 246 | $F2psEnd 247 | rs 248 | -------------------------------------------------------------------------------- /vb_fakesource.cc: -------------------------------------------------------------------------------- 1 | // vb_fakesource.cc 2 | // Crude simulator for a VIRAQ-based bistatic receiver 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // Copyright © 2000 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | # include 29 | # include 30 | # include 31 | # include 32 | # include 33 | # include "VIRAQ_Beam.hh" 34 | 35 | // 36 | // Make sure that PRT*HITS divides evenly into 60 * 8000000 (This forces 37 | // a new beam to start at the top of each minute, and makes math 38 | // bearable below. Remember that this is just a testing program...) 39 | // 40 | const int PRT = 8000; 41 | const int HITS = 60; 42 | const int NGATES = 250; 43 | 44 | VIRAQ_Hdr Hdr; 45 | VIRAQ_RHdr RHdr; 46 | int Socket; 47 | 48 | void nextbeam( int junk ); 49 | void sendout( const char* data, int len ); 50 | 51 | 52 | int main( int argc, char *argv[] ) 53 | { 54 | // 55 | // Sanity checks 56 | // 57 | if (argc != 2) 58 | { 59 | fprintf( stderr, "Usage: %s \n", argv[0] ); 60 | exit( 1 ); 61 | } 62 | 63 | assert ((60 * 8000000) % (PRT * HITS) == 0); 64 | // 65 | // Open our outgoing socket 66 | // 67 | if ((Socket = socket( AF_INET, SOCK_DGRAM, 0 )) < 0) 68 | { 69 | fprintf( stderr, "Error %d creating or configuring command socket\n", 70 | errno ); 71 | exit (1); 72 | } 73 | 74 | int one = 1; 75 | if (setsockopt(Socket, SOL_SOCKET, SO_BROADCAST, (void*)&one, 76 | sizeof(one)) != 0) 77 | fprintf( stderr, "Cannot set SO_BROADCAST flag for socket\n" ); 78 | // 79 | // Set up the recipient's address using the given host name 80 | // and the VIRAQ data port (0x6006) 81 | // 82 | struct sockaddr_in to; 83 | memset( (char*)&to, 0, sizeof( to ) ); 84 | to.sin_family = AF_INET; 85 | to.sin_port = htons( 0x6006 ); 86 | inet_pton( AF_INET, argv[1], &to.sin_addr ); 87 | 88 | if (connect( Socket, (struct sockaddr*)&to, sizeof( to ) ) < 0) 89 | { 90 | fprintf( stderr, 91 | "Error %d associating address %s with the data socket\n", 92 | errno, argv[1] ); 93 | exit( 1 ); 94 | } 95 | // 96 | // per-beam header stuff that will remain constant 97 | // 98 | strncpy( Hdr.desc, "DWEL", 4 ); 99 | Hdr.recordlen = (short)(VIRAQ_HdrLen + NGATES * 12); 100 | Hdr.gates = (short)NGATES; 101 | Hdr.hits = (short)HITS; 102 | Hdr.rcvr_pulsewidth = 2.0e-6; 103 | Hdr.prt = PRT / 8000000.0; 104 | Hdr.delay = 0.0; 105 | Hdr.clutterfilter = (char)0; 106 | Hdr.timeseries = (char)0; 107 | Hdr.tsgate = (short)0; 108 | Hdr.radar_longitude = 0.0; 109 | Hdr.radar_latitude = 0.0; 110 | Hdr.radar_altitude = 0.0; 111 | Hdr.ew_velocity = 0.0; 112 | Hdr.ns_velocity = 0.0; 113 | Hdr.vert_velocity = 0.0; 114 | Hdr.dataformat = (unsigned char)0; // DATA_SIMPLEPP 115 | Hdr.prt2 = 0.0; 116 | Hdr.scan_type = (unsigned char)8; // SUR 117 | Hdr.transition = (char)0; 118 | Hdr.hxmit_power = 1.0e6; 119 | Hdr.vxmit_power = 1.0e6; 120 | memset( Hdr.spare, 0, 100 ); 121 | // 122 | // "Radar" header stuff; also constant 123 | // 124 | strncpy( RHdr.desc, "RHDR", 4 ); 125 | RHdr.recordlen = (short)VIRAQ_RHdrLen; 126 | RHdr.rev = (short)0; 127 | RHdr.year = (short)1999; 128 | strncpy( RHdr.radar_name, "BOGUS ", 8 ); 129 | RHdr.polarization = 'V'; 130 | RHdr.test_pulse_pwr = 0.0; 131 | RHdr.test_pulse_frq = 0.0; 132 | RHdr.frequency = 5.5e9; 133 | RHdr.peak_power = 1.0e6; 134 | RHdr.noise_figure = 0.0; 135 | RHdr.noise_power = 0.0; 136 | RHdr.receiver_gain = 60.0; 137 | RHdr.data_sys_sat = -2.5; 138 | RHdr.antenna_gain = 40.0; 139 | RHdr.horz_beam_width = 1.0; 140 | RHdr.vert_beam_width = 1.0; 141 | RHdr.xmit_pulsewidth = 1.0e-6; 142 | RHdr.rconst = 70.0; 143 | RHdr.phaseoffset = 0.0; 144 | RHdr.vreceiver_gain = 60.0; 145 | RHdr.test_pulse_pwr = 0.0; 146 | RHdr.vantenna_gain = 40.0; 147 | memset( RHdr.misc, 0, 24 ); 148 | memset( RHdr.text, 0, 960 ); 149 | // 150 | // Catch the ALRM signal, and set an interval timer 151 | // 152 | signal( SIGALRM, nextbeam ); 153 | 154 | struct itimerval itv; 155 | itv.it_interval.tv_sec = 0; 156 | itv.it_interval.tv_usec = (PRT * HITS) / 8; 157 | itv.it_value.tv_sec = 0; 158 | itv.it_value.tv_usec = 1; 159 | 160 | setitimer( ITIMER_REAL, &itv, 0 ); 161 | 162 | while (1) 163 | { 164 | pause(); 165 | } 166 | } 167 | 168 | 169 | void 170 | nextbeam( int junk ) 171 | { 172 | static int lastvol = -1; 173 | static char* buf = 0; 174 | static LE_Float* data = 0; 175 | 176 | if (! buf) 177 | { 178 | buf = new char[sizeof( Hdr ) + 3 * sizeof( LE_Float ) * NGATES]; 179 | LE_Float* data = (LE_Float*)(buf + sizeof( Hdr )); 180 | // 181 | // A, B, P in "simplepp" form 182 | // 183 | float p = 1.0e17; 184 | float a = 0.5 * p; 185 | float b = 0.0 * p; 186 | 187 | for (int g = 0; g < NGATES; g++) 188 | { 189 | data[3*g] = a; 190 | data[3*g+1] = b; 191 | data[3*g+2] = p; 192 | } 193 | } 194 | // 195 | // Get current time and figure out the beam number within this minute. 196 | // (The assertion in main guarantees that a new beam starts exactly at 197 | // the top of each minute) 198 | // 199 | struct timeval tv; 200 | gettimeofday( &tv, 0 ); 201 | unsigned long sec_in_minute = tv.tv_sec % 60; 202 | unsigned long beamnum = (8000000 * sec_in_minute + 8 * tv.tv_usec) / 203 | (PRT * HITS); 204 | // 205 | // Get the time for this beam and put it in the header 206 | // 207 | unsigned long minute = tv.tv_sec / 60; 208 | double beamtime = (double)(beamnum * PRT * HITS) / 8e6; 209 | unsigned long ibeamtime = (unsigned long) beamtime; 210 | 211 | Hdr.time = minute * 60 + ibeamtime; 212 | Hdr.subsec = (short)((beamtime - ibeamtime) * 10000); 213 | // 214 | // Two minute volumes with four sweeps per volume, 500 beams/sweep, 215 | // and elevations: 0.5, 1.5, 2.5, and 3.5 degrees. 216 | // 217 | int sweep = (tv.tv_sec / 30) % 4; 218 | Hdr.az = (beamnum % 500) / 500.0 * 360.0; 219 | Hdr.el = sweep + 0.5; 220 | Hdr.fxd_angle = Hdr.el; 221 | Hdr.scan_num = sweep; 222 | Hdr.vol_num = (unsigned char)((minute/2) & 0xff); 223 | Hdr.ray_count = beamnum & 0x7fffffff; 224 | // 225 | // Send out a RHdr before each volume 226 | // 227 | if (Hdr.vol_num.Value() != lastvol) 228 | { 229 | lastvol = Hdr.vol_num.Value(); 230 | sendout( (char*)&RHdr, VIRAQ_RHdrLen ); 231 | } 232 | // 233 | // Send the data header and data 234 | // 235 | memmove( buf, &Hdr, sizeof( Hdr ) ); 236 | sendout( buf, sizeof( Hdr ) + 3 * sizeof( LE_Float ) * NGATES ); 237 | 238 | signal( SIGALRM, nextbeam ); 239 | } 240 | 241 | 242 | 243 | void 244 | sendout( const char* data, int len ) 245 | { 246 | int nsent = 0; 247 | const int PKTSIZE = 1000; // break data into packets of this size 248 | static int pktsequence = 0; 249 | // 250 | // per-packet header 251 | // 252 | typedef struct _UDPHeader 253 | { 254 | short type; // first or continue 255 | long sequence; 256 | short frames_per_radial; 257 | short frame_num; 258 | } UDPHeader; 259 | UDPHeader udphdr = { 0, 0, 0, 0 }; 260 | 261 | char buf[PKTSIZE + sizeof( UDPHeader )]; 262 | 263 | int npkts = (len + PKTSIZE - 1) / PKTSIZE; 264 | for (int pkt = 0; pkt < npkts; pkt++) 265 | { 266 | udphdr.sequence = pktsequence++; 267 | udphdr.frames_per_radial = npkts; 268 | udphdr.frame_num = pkt; 269 | 270 | int dstart = pkt * PKTSIZE; 271 | int dlen = (len - dstart) > 1000 ? 1000 : (len - dstart); 272 | 273 | memmove( buf, &udphdr, sizeof( udphdr ) ); 274 | memmove( buf + sizeof( udphdr ), data + dstart, dlen ); 275 | 276 | int n = send( Socket, buf, dlen + sizeof( udphdr ), 0 ); 277 | // 278 | // Exit on errors, except "Connection refused" 279 | // 280 | if (n < 0 && errno != ECONNREFUSED) 281 | { 282 | perror("data send"); 283 | exit( 1 ); 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /MergedBeam.hh: -------------------------------------------------------------------------------- 1 | // MergedBeam.hh 2 | // This is the form of a merged bistatic beam 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | 21 | # ifndef _MERGEDBEAM_HH_ 22 | # define _MERGEDBEAM_HH_ 23 | 24 | # include 25 | # include "Beam.hh" 26 | 27 | 28 | class MergedBeam : public Beam 29 | { 30 | public: 31 | MergedBeam( const Beam* beams[], int nbeams, float ncp_thresh = 0.0 ); 32 | ~MergedBeam( void ); 33 | inline int NumMembers( void ) const { return NMembers; } 34 | // usable beam? 35 | int OK( void ) const; 36 | // beam time, seconds since 1-Jan-1970,00:00 UTC 37 | double Time( void ) const; 38 | // number of gates 39 | int Gates( void ) const; 40 | int Gates( int rcvr ) const; 41 | // receiver pulsewidth, seconds 42 | float RcvrPulseWidth( void ) const; 43 | float RcvrPulseWidth( int rcvr ) const; 44 | // range to center of first gate, meters 45 | float RangeToFirstGate( void ) const; 46 | float RangeToFirstGate( int rcvr ) const; 47 | // beam azimuth, degrees clockwise from true north 48 | float Azimuth( void ) const; 49 | // beam elevation, degrees above horizontal 50 | float Elevation( void ) const; 51 | // fixed angle, degrees 52 | float FixedAngle( void ) const; 53 | // transmitter frequency, Hz 54 | float Frequency( void ) const; 55 | // xmit pulse repetition time, seconds 56 | float PRT( void ) const; 57 | // number of hits 58 | int Hits( void ) const; 59 | int Hits( int rcvr ) const; 60 | // receiver 61 | const Receiver* Rcvr( void ) const; 62 | const Receiver* Rcvr( int rcvr ) const; 63 | // lat 64 | float RadarLat( void ) const; 65 | float RadarLat( int rcvr ) const; 66 | // lon 67 | float RadarLon( void ) const; 68 | float RadarLon( int rcvr ) const; 69 | // alt 70 | float RadarAlt( void ) const; 71 | float RadarAlt( int rcvr ) const; 72 | // delay between xmit pulse and sample start, seconds 73 | float Delay( void ) const; 74 | float Delay( int rcvr ) const; 75 | // volume number 76 | int VolNum( void ) const; 77 | // sweep number 78 | int SweepNum( void ) const; 79 | // scan type 80 | const char* ScanType( void ) const; 81 | // get a format-specific information string 82 | const char* Info( void ) const; 83 | // raw velocity data 84 | const void* VelRaw( DataType *type, int *step, float *scale, 85 | float *offset ) const; 86 | const void* VelRaw( DataType *type, int *step, float *scale, 87 | float *offset, int rcvr ) const; 88 | // raw reflectivity data 89 | const void* dBZRaw( DataType *type, int *step, float *scale, 90 | float *offset ) const; 91 | const void* dBZRaw( DataType *type, int *step, float *scale, 92 | float *offset, int rcvr ) const; 93 | // raw power data 94 | const void* dBmRaw( DataType *type, int *step, float *scale, 95 | float *offset ) const; 96 | const void* dBmRaw( DataType *type, int *step, float *scale, 97 | float *offset, int rcvr ) const; 98 | // raw NCP data 99 | const void* NCPRaw( DataType *type, int *step, float *scale, 100 | float *offset ) const; 101 | const void* NCPRaw( DataType *type, int *step, float *scale, 102 | float *offset, int rcvr ) const; 103 | // non-raw data methods 104 | int VelData( float* data, int maxlen, float badval, int rcvr ) const; 105 | int dBZData( float* data, int maxlen, float badval, int rcvr ) const; 106 | int dBmData( float* data, int maxlen, float badval, int rcvr ) const; 107 | int NCPData( float* data, int maxlen, float badval, int rcvr ) const; 108 | // u and v wind data (calculated using receiver 0 and the receiver specified) 109 | int UWindData( float* data, int maxlen, float badval, int rcvr ) const; 110 | int VWindData( float* data, int maxlen, float badval, int rcvr ) const; 111 | // best u and v 112 | int UBestData( float* data, int maxlen, float badval ) const; 113 | int VBestData( float* data, int maxlen, float badval ) const; 114 | private: 115 | Beam** Members; 116 | int NMembers; 117 | float NCPThresh; // NCP threshold for acceptable winds 118 | float** U; // U[NMembers][ngates] 119 | float** V; // V[NMembers][ngates] 120 | float* UBest; // UBest[ngates] 121 | float* VBest; // VBest[ngates] 122 | 123 | static constexpr float VelMax = 200.0; 124 | static constexpr float VelScale = VelMax / 32767.0; // fits +-VelMax into int16_t 125 | 126 | static constexpr float FBADVAL = -MAXFLOAT; 127 | static constexpr int16_t SBADVAL = MINSHORT; 128 | 129 | void RcvrGateAndAz( int x_gate, int rcvr, int *r_gate, float *r_az, 130 | float phi, float sin_phi, float cos_phi ); 131 | void DeriveWinds( void ); 132 | }; 133 | 134 | 135 | // 136 | // A bunch of stuff is inlined 137 | // 138 | inline double 139 | MergedBeam::Time( void ) const 140 | { 141 | return Members[0]->Time(); 142 | } 143 | 144 | inline int 145 | MergedBeam::Gates( void ) const 146 | { 147 | return Gates( 0 ); 148 | } 149 | 150 | inline int 151 | MergedBeam::Gates( int rcvr ) const 152 | { 153 | return Members[rcvr]->Gates(); 154 | } 155 | 156 | inline float 157 | MergedBeam::RcvrPulseWidth( void ) const 158 | { 159 | return RcvrPulseWidth( 0 ); 160 | } 161 | 162 | inline float 163 | MergedBeam::RcvrPulseWidth( int rcvr ) const 164 | { 165 | return Members[rcvr]->RcvrPulseWidth(); 166 | } 167 | 168 | inline float 169 | MergedBeam::RangeToFirstGate( void ) const 170 | { 171 | return RangeToFirstGate( 0 ); 172 | } 173 | 174 | inline float 175 | MergedBeam::RangeToFirstGate( int rcvr ) const 176 | { 177 | return Members[rcvr]->RangeToFirstGate(); 178 | } 179 | 180 | inline float 181 | MergedBeam::Azimuth( void ) const 182 | { 183 | return Members[0]->Azimuth(); 184 | } 185 | 186 | inline float 187 | MergedBeam::Elevation( void ) const 188 | { 189 | return Members[0]->Elevation(); 190 | } 191 | 192 | inline float 193 | MergedBeam::FixedAngle( void ) const 194 | { 195 | return Members[0]->FixedAngle(); 196 | } 197 | 198 | inline float 199 | MergedBeam::Frequency( void ) const 200 | { 201 | return Members[0]->Frequency(); 202 | } 203 | 204 | inline float 205 | MergedBeam::PRT( void ) const 206 | { 207 | return Members[0]->PRT(); 208 | } 209 | 210 | inline int 211 | MergedBeam::Hits( void ) const 212 | { 213 | return Hits( 0 ); 214 | } 215 | 216 | inline int 217 | MergedBeam::Hits( int rcvr ) const 218 | { 219 | return Members[rcvr]->Hits(); 220 | } 221 | 222 | inline const Receiver* 223 | MergedBeam::Rcvr( void ) const 224 | { 225 | return Rcvr( 0 ); 226 | } 227 | 228 | inline const Receiver* 229 | MergedBeam::Rcvr( int rcvr ) const 230 | { 231 | return Members[rcvr]->Rcvr(); 232 | } 233 | 234 | inline float 235 | MergedBeam::RadarLat( void ) const 236 | { 237 | return RadarLat( 0 ); 238 | } 239 | 240 | inline float 241 | MergedBeam::RadarLat( int rcvr ) const 242 | { 243 | return Members[rcvr]->RadarLat(); 244 | } 245 | 246 | inline float 247 | MergedBeam::RadarLon( void ) const 248 | { 249 | return RadarLon( 0 ); 250 | } 251 | 252 | inline float 253 | MergedBeam::RadarLon( int rcvr ) const 254 | 255 | { 256 | return Members[rcvr]->RadarLon(); 257 | } 258 | 259 | inline float 260 | MergedBeam::RadarAlt( void ) const 261 | { 262 | return RadarAlt( 0 ); 263 | } 264 | 265 | inline float 266 | MergedBeam::RadarAlt( int rcvr ) const 267 | { 268 | return Members[rcvr]->RadarAlt(); 269 | } 270 | 271 | inline float 272 | MergedBeam::Delay( void ) const 273 | { 274 | return Delay( 0 ); 275 | } 276 | 277 | inline float 278 | MergedBeam::Delay( int rcvr ) const 279 | { 280 | return Members[rcvr]->Delay(); 281 | } 282 | 283 | inline int 284 | MergedBeam::VolNum( void ) const 285 | { 286 | return Members[0]->VolNum(); 287 | } 288 | 289 | inline int 290 | MergedBeam::SweepNum( void ) const 291 | { 292 | return Members[0]->SweepNum(); 293 | } 294 | 295 | inline const char* 296 | MergedBeam::ScanType( void ) const 297 | { 298 | return Members[0]->ScanType(); 299 | } 300 | 301 | inline const char* 302 | MergedBeam::Info( void ) const 303 | { 304 | return "merged beam"; 305 | } 306 | 307 | inline const void* 308 | MergedBeam::VelRaw( DataType *type, int *step, float *scale, 309 | float *offset ) const 310 | { 311 | return VelRaw( type, step, scale, offset, 0 ); 312 | } 313 | 314 | inline const void* 315 | MergedBeam::VelRaw( DataType *type, int *step, float *scale, float *offset, 316 | int rcvr ) const 317 | { 318 | return Members[rcvr]->VelRaw( type, step, scale, offset ); 319 | } 320 | 321 | inline const void* 322 | MergedBeam::dBZRaw( DataType *type, int *step, float *scale, 323 | float *offset ) const 324 | { 325 | return dBZRaw( type, step, scale, offset, 0 ); 326 | } 327 | 328 | inline const void* 329 | MergedBeam::dBZRaw( DataType *type, int *step, float *scale, 330 | float *offset, int rcvr ) const 331 | { 332 | return Members[rcvr]->dBZRaw( type, step, scale, offset ); 333 | } 334 | 335 | inline const void* 336 | MergedBeam::dBmRaw( DataType *type, int *step, float *scale, 337 | float *offset ) const 338 | { 339 | return dBmRaw( type, step, scale, offset, 0 ); 340 | } 341 | 342 | inline const void* 343 | MergedBeam::dBmRaw( DataType *type, int *step, float *scale, 344 | float *offset, int rcvr ) const 345 | { 346 | return Members[rcvr]->dBmRaw( type, step, scale, offset ); 347 | } 348 | 349 | inline const void* 350 | MergedBeam::NCPRaw( DataType *type, int *step, float *scale, 351 | float *offset ) const 352 | { 353 | return NCPRaw( type, step, scale, offset, 0 ); 354 | } 355 | 356 | inline const void* 357 | MergedBeam::NCPRaw( DataType *type, int *step, float *scale, 358 | float *offset, int rcvr ) const 359 | { 360 | return Members[rcvr]->NCPRaw( type, step, scale, offset ); 361 | } 362 | 363 | inline int 364 | MergedBeam::VelData( float* data, int maxlen, float badval, int rcvr ) const 365 | { 366 | return Members[rcvr]->VelData( data, maxlen, badval ); 367 | } 368 | 369 | inline int 370 | MergedBeam::dBZData( float* data, int maxlen, float badval, int rcvr ) const 371 | { 372 | return Members[rcvr]->dBZData( data, maxlen, badval ); 373 | } 374 | 375 | inline int 376 | MergedBeam::dBmData( float* data, int maxlen, float badval, int rcvr ) const 377 | { 378 | return Members[rcvr]->dBmData( data, maxlen, badval ); 379 | } 380 | 381 | inline int 382 | MergedBeam::NCPData( float* data, int maxlen, float badval, int rcvr ) const 383 | { 384 | 385 | return Members[rcvr]->NCPData( data, maxlen, badval ); 386 | } 387 | 388 | # endif // _MERGEDBEAM_HH_ 389 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | # Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. 4 | # Originally by Fran,cois Pinard , 1996. 5 | 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2, or (at your option) 9 | # any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | # 02111-1307, USA. 20 | 21 | # As a special exception to the GNU General Public License, if you 22 | # distribute this file as part of a program that contains a 23 | # configuration script generated by Autoconf, you may include it under 24 | # the same distribution terms that you use for the rest of that program. 25 | 26 | if test $# -eq 0; then 27 | echo 1>&2 "Try \`$0 --help' for more information" 28 | exit 1 29 | fi 30 | 31 | run=: 32 | 33 | # In the cases where this matters, `missing' is being run in the 34 | # srcdir already. 35 | if test -f configure.ac; then 36 | configure_ac=configure.ac 37 | else 38 | configure_ac=configure.in 39 | fi 40 | 41 | case "$1" in 42 | --run) 43 | # Try to run requested program, and just exit if it succeeds. 44 | run= 45 | shift 46 | "$@" && exit 0 47 | ;; 48 | esac 49 | 50 | # If it does not exist, or fails to run (possibly an outdated version), 51 | # try to emulate it. 52 | case "$1" in 53 | 54 | -h|--h|--he|--hel|--help) 55 | echo "\ 56 | $0 [OPTION]... PROGRAM [ARGUMENT]... 57 | 58 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 59 | error status if there is no known handling for PROGRAM. 60 | 61 | Options: 62 | -h, --help display this help and exit 63 | -v, --version output version information and exit 64 | --run try to run the given command, and emulate it if it fails 65 | 66 | Supported PROGRAM values: 67 | aclocal touch file \`aclocal.m4' 68 | autoconf touch file \`configure' 69 | autoheader touch file \`config.h.in' 70 | automake touch all \`Makefile.in' files 71 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 72 | flex create \`lex.yy.c', if possible, from existing .c 73 | help2man touch the output file 74 | lex create \`lex.yy.c', if possible, from existing .c 75 | makeinfo touch the output file 76 | tar try tar, gnutar, gtar, then tar without non-portable flags 77 | yacc create \`y.tab.[ch]', if possible, from existing .[ch]" 78 | ;; 79 | 80 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 81 | echo "missing 0.4 - GNU automake" 82 | ;; 83 | 84 | -*) 85 | echo 1>&2 "$0: Unknown \`$1' option" 86 | echo 1>&2 "Try \`$0 --help' for more information" 87 | exit 1 88 | ;; 89 | 90 | aclocal*) 91 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 92 | # We have it, but it failed. 93 | exit 1 94 | fi 95 | 96 | echo 1>&2 "\ 97 | WARNING: \`$1' is missing on your system. You should only need it if 98 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 99 | to install the \`Automake' and \`Perl' packages. Grab them from 100 | any GNU archive site." 101 | touch aclocal.m4 102 | ;; 103 | 104 | autoconf) 105 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 106 | # We have it, but it failed. 107 | exit 1 108 | fi 109 | 110 | echo 1>&2 "\ 111 | WARNING: \`$1' is missing on your system. You should only need it if 112 | you modified \`${configure_ac}'. You might want to install the 113 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 114 | archive site." 115 | touch configure 116 | ;; 117 | 118 | autoheader) 119 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 120 | # We have it, but it failed. 121 | exit 1 122 | fi 123 | 124 | echo 1>&2 "\ 125 | WARNING: \`$1' is missing on your system. You should only need it if 126 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 127 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 128 | from any GNU archive site." 129 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 130 | test -z "$files" && files="config.h" 131 | touch_files= 132 | for f in $files; do 133 | case "$f" in 134 | *:*) touch_files="$touch_files "`echo "$f" | 135 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 136 | *) touch_files="$touch_files $f.in";; 137 | esac 138 | done 139 | touch $touch_files 140 | ;; 141 | 142 | automake*) 143 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 144 | # We have it, but it failed. 145 | exit 1 146 | fi 147 | 148 | echo 1>&2 "\ 149 | WARNING: \`$1' is missing on your system. You should only need it if 150 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 151 | You might want to install the \`Automake' and \`Perl' packages. 152 | Grab them from any GNU archive site." 153 | find . -type f -name Makefile.am -print | 154 | sed 's/\.am$/.in/' | 155 | while read f; do touch "$f"; done 156 | ;; 157 | 158 | autom4te) 159 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 160 | # We have it, but it failed. 161 | exit 1 162 | fi 163 | 164 | echo 1>&2 "\ 165 | WARNING: \`$1' is needed, and you do not seem to have it handy on your 166 | system. You might have modified some files without having the 167 | proper tools for further handling them. 168 | You can get \`$1Help2man' as part of \`Autoconf' from any GNU 169 | archive site." 170 | 171 | file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` 172 | test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` 173 | if test -f "$file"; then 174 | touch $file 175 | else 176 | test -z "$file" || exec >$file 177 | echo "#! /bin/sh" 178 | echo "# Created by GNU Automake missing as a replacement of" 179 | echo "# $ $@" 180 | echo "exit 0" 181 | chmod +x $file 182 | exit 1 183 | fi 184 | ;; 185 | 186 | bison|yacc) 187 | echo 1>&2 "\ 188 | WARNING: \`$1' is missing on your system. You should only need it if 189 | you modified a \`.y' file. You may need the \`Bison' package 190 | in order for those modifications to take effect. You can get 191 | \`Bison' from any GNU archive site." 192 | rm -f y.tab.c y.tab.h 193 | if [ $# -ne 1 ]; then 194 | eval LASTARG="\${$#}" 195 | case "$LASTARG" in 196 | *.y) 197 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 198 | if [ -f "$SRCFILE" ]; then 199 | cp "$SRCFILE" y.tab.c 200 | fi 201 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 202 | if [ -f "$SRCFILE" ]; then 203 | cp "$SRCFILE" y.tab.h 204 | fi 205 | ;; 206 | esac 207 | fi 208 | if [ ! -f y.tab.h ]; then 209 | echo >y.tab.h 210 | fi 211 | if [ ! -f y.tab.c ]; then 212 | echo 'main() { return 0; }' >y.tab.c 213 | fi 214 | ;; 215 | 216 | lex|flex) 217 | echo 1>&2 "\ 218 | WARNING: \`$1' is missing on your system. You should only need it if 219 | you modified a \`.l' file. You may need the \`Flex' package 220 | in order for those modifications to take effect. You can get 221 | \`Flex' from any GNU archive site." 222 | rm -f lex.yy.c 223 | if [ $# -ne 1 ]; then 224 | eval LASTARG="\${$#}" 225 | case "$LASTARG" in 226 | *.l) 227 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 228 | if [ -f "$SRCFILE" ]; then 229 | cp "$SRCFILE" lex.yy.c 230 | fi 231 | ;; 232 | esac 233 | fi 234 | if [ ! -f lex.yy.c ]; then 235 | echo 'main() { return 0; }' >lex.yy.c 236 | fi 237 | ;; 238 | 239 | help2man) 240 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 241 | # We have it, but it failed. 242 | exit 1 243 | fi 244 | 245 | echo 1>&2 "\ 246 | WARNING: \`$1' is missing on your system. You should only need it if 247 | you modified a dependency of a manual page. You may need the 248 | \`Help2man' package in order for those modifications to take 249 | effect. You can get \`Help2man' from any GNU archive site." 250 | 251 | file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` 252 | if test -z "$file"; then 253 | file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` 254 | fi 255 | if [ -f "$file" ]; then 256 | touch $file 257 | else 258 | test -z "$file" || exec >$file 259 | echo ".ab help2man is required to generate this page" 260 | exit 1 261 | fi 262 | ;; 263 | 264 | makeinfo) 265 | if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then 266 | # We have makeinfo, but it failed. 267 | exit 1 268 | fi 269 | 270 | echo 1>&2 "\ 271 | WARNING: \`$1' is missing on your system. You should only need it if 272 | you modified a \`.texi' or \`.texinfo' file, or any other file 273 | indirectly affecting the aspect of the manual. The spurious 274 | call might also be the consequence of using a buggy \`make' (AIX, 275 | DU, IRIX). You might want to install the \`Texinfo' package or 276 | the \`GNU make' package. Grab either from any GNU archive site." 277 | file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` 278 | if test -z "$file"; then 279 | file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 280 | file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` 281 | fi 282 | touch $file 283 | ;; 284 | 285 | tar) 286 | shift 287 | if test -n "$run"; then 288 | echo 1>&2 "ERROR: \`tar' requires --run" 289 | exit 1 290 | fi 291 | 292 | # We have already tried tar in the generic part. 293 | # Look for gnutar/gtar before invocation to avoid ugly error 294 | # messages. 295 | if (gnutar --version > /dev/null 2>&1); then 296 | gnutar "$@" && exit 0 297 | fi 298 | if (gtar --version > /dev/null 2>&1); then 299 | gtar "$@" && exit 0 300 | fi 301 | firstarg="$1" 302 | if shift; then 303 | case "$firstarg" in 304 | *o*) 305 | firstarg=`echo "$firstarg" | sed s/o//` 306 | tar "$firstarg" "$@" && exit 0 307 | ;; 308 | esac 309 | case "$firstarg" in 310 | *h*) 311 | firstarg=`echo "$firstarg" | sed s/h//` 312 | tar "$firstarg" "$@" && exit 0 313 | ;; 314 | esac 315 | fi 316 | 317 | echo 1>&2 "\ 318 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 319 | You may want to install GNU tar or Free paxutils, or check the 320 | command line arguments." 321 | exit 1 322 | ;; 323 | 324 | *) 325 | echo 1>&2 "\ 326 | WARNING: \`$1' is needed, and you do not seem to have it handy on your 327 | system. You might have modified some files without having the 328 | proper tools for further handling them. Check the \`README' file, 329 | it often tells you about the needed prerequirements for installing 330 | this package. You may also peek at any GNU archive site, in case 331 | some other package would contain this missing \`$1' program." 332 | exit 1 333 | ;; 334 | esac 335 | 336 | exit 0 337 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | -------------------------------------------------------------------------------- /PB_Beam.cc: -------------------------------------------------------------------------------- 1 | // PB_Beam.cc 2 | // This is the form of the PIRAQ bistatic beam 3 | // 4 | // Copyright © 1998 Binet Incorporated 5 | // Copyright © 1998 University Corporation for Atmospheric Research 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | # include 22 | # include 23 | # include 24 | # include 25 | # include "PB_Beam.hh" 26 | # include "Receiver.hh" 27 | 28 | const float _C_ = 2.998e8; // m/s 29 | 30 | 31 | float PB_Beam::PB_Frequency = 1.0; 32 | 33 | // 34 | // PIRAQ bistatic (short header) beams 35 | // 36 | 37 | 38 | 39 | PB_Beam::PB_Beam( char* inbuf, int& inbuflen, const Receiver* rcvr ) 40 | // 41 | // Construct a PB_Beam from the given buffer. Upon return, any data we have 42 | // used or skipped is removed from the buffer, with the remainder shifted to 43 | // the head of the buffer. The inbuflen is adjusted accordingly. 44 | // 45 | { 46 | int beamlen = inbuflen; // until we know the real size 47 | int nskipped = 0; 48 | int datalen = 0; 49 | // 50 | // Pointer to the beginning of the beam-in-progress, interpreted as 51 | // a PB_Hdr 52 | // 53 | PB_Hdr *curhdr = (PB_Hdr*)inbuf; 54 | // 55 | // Set our data pointers to null until we have a good beam 56 | // 57 | Data = 0; 58 | UnpackedPwr = 0; 59 | UnpackedNCP = 0; 60 | // 61 | // If our partial beam does not begin with 'PRQ', we've got to look for 62 | // it. 63 | // 64 | if (inbuflen >= 3 && strncmp( inbuf, "PRQ", 3 )) 65 | { 66 | // 67 | // We need to look for the "PRQ" magic cookie somewhere within the 68 | // buffer. We don't check the last two bytes, since the cookie is 69 | // three bytes long. If we find "PRQ", shift so that it's at the 70 | // beginning of inbuf, otherwise just move the last two bytes to 71 | // the beginning of inbuf. 72 | // 73 | char *c = inbuf + 1; 74 | while (1) 75 | { 76 | if (! (c = (char*) memchr( c, 'P', inbuf + inbuflen - c ))) 77 | { 78 | c = inbuf + inbuflen - 2; 79 | break; 80 | } 81 | 82 | if (! strncmp( c, "PRQ", 3 )) 83 | break; 84 | 85 | c++; 86 | } 87 | 88 | inbuflen = inbuf + inbuflen - c; 89 | nskipped += c - inbuf; 90 | memmove( inbuf, c, inbuflen ); 91 | } 92 | // 93 | // If we have a full PB_Hdr worth, verify the header-ending 'X' byte and 94 | // figure out our true beam length 95 | // 96 | if (inbuflen >= PB_HdrLen) 97 | { 98 | // 99 | // If we don't have the appropriate trailing X, just overwrite the 100 | // 'P' of 'PRQ' and continue. 101 | // 102 | if (curhdr->trailer.Value() != 'X') 103 | { 104 | fprintf( stderr, "PB_Beam: no trailing 'X' in header!\n" ); 105 | inbuf[0] = '\0'; 106 | return; 107 | } 108 | // 109 | // Figure out the data length by summing the length for each field present 110 | // 111 | unsigned char format = curhdr->format.Value(); 112 | int ngates = curhdr->ngates.Value(); 113 | 114 | for (int i = 0; i < 8; i++) 115 | { 116 | if (format & (1 << i)) 117 | { 118 | int nbytes = ngates * PBFormatInfo[i].bytes_per_gate; 119 | 120 | if (nbytes) 121 | datalen += nbytes; 122 | else 123 | { 124 | fprintf( stderr, 125 | "PB_Beam::PB_Beam: Bad bit %d set in format!\n", 126 | i ); 127 | inbuf[0] = '\0'; 128 | return; 129 | } 130 | } 131 | } 132 | // 133 | // Total beam length 134 | // 135 | beamlen = datalen + PB_HdrLen; 136 | } 137 | // 138 | // If we don't have a full beam of data, just return now 139 | // 140 | if (inbuflen < beamlen) 141 | return; 142 | // 143 | // If we get here, we should have a complete beam available in our buffer. 144 | // 145 | // Report on how much stuff we skipped to get here. 146 | // 147 | if (nskipped) 148 | fprintf( stderr, "Skipped %d to find PRQ", nskipped ); 149 | // 150 | // Copy the beginning of our beam-in-progress buffer into our header. 151 | // 152 | Hdr = *curhdr; 153 | // 154 | // Allocate data space, and copy the data over from the beam-in-progress 155 | // buffer. 156 | // 157 | Data = new char[datalen]; 158 | memmove( Data, inbuf + PB_HdrLen, datalen ); 159 | // 160 | // Move any remaining data in the beam-in-progress to the head of the line. 161 | // 162 | memmove( inbuf, inbuf + beamlen, inbuflen - beamlen ); 163 | inbuflen -= beamlen; 164 | // 165 | // Set our clock count time. Either 1/8 microsecond for version 1 format, 166 | // or 1/10 microsecond for version 2. 167 | // 168 | ClockCountTime = (Hdr.version.Value() == 1) ? 1.25e-7 : 1.00e-7; 169 | // 170 | // Stash our Receiver pointer 171 | // 172 | MyReceiver = rcvr; 173 | // 174 | // Unpack the packed power/NCP field if we have it 175 | // 176 | UnpackP_NCP(); 177 | // 178 | // We're done! 179 | // 180 | return; 181 | } 182 | 183 | 184 | 185 | PB_Beam::~PB_Beam( void ) 186 | { 187 | delete[] Data; 188 | if (UnpackedPwr) 189 | delete[] UnpackedPwr; 190 | if (UnpackedNCP) 191 | delete[] UnpackedNCP; 192 | } 193 | 194 | 195 | 196 | int 197 | PB_Beam::OK( void ) const 198 | { 199 | // 200 | // We consider ourselves OK if we have a real pointer to some data 201 | // 202 | return( Data != NULL ); 203 | } 204 | 205 | 206 | 207 | double 208 | PB_Beam::Time( void ) const 209 | { 210 | return (double)(Hdr.time.Value() + 0.0001 * Hdr.subsec.Value()); 211 | } 212 | 213 | 214 | int 215 | PB_Beam::Gates( void ) const 216 | { 217 | return (int)(Hdr.ngates.Value()); 218 | } 219 | 220 | 221 | 222 | float 223 | PB_Beam::RcvrPulseWidth( void ) const 224 | { 225 | return (float)(ClockCountTime * Hdr.pulsewidth.Value()); 226 | } 227 | 228 | 229 | 230 | float 231 | PB_Beam::RangeToFirstGate( void ) const 232 | // 233 | // Note that this value will normally be negative for bistatic receivers, 234 | // since under normal circumstances they begin sampling before the arrival 235 | // of the transmit pulse. 236 | // 237 | { 238 | return( Delay() * _C_ - MyReceiver->RangeFromRadar() + 239 | 0.5 * RcvrPulseWidth() * _C_ ); 240 | } 241 | 242 | 243 | 244 | float 245 | PB_Beam::Azimuth( void ) const 246 | { 247 | return (float)(Hdr.azimuth.Value() * 360.0 / 65536); 248 | } 249 | 250 | 251 | 252 | 253 | float 254 | PB_Beam::Elevation( void ) const 255 | { 256 | return (float)(Hdr.elevation.Value() * 360.0 / 65536); 257 | } 258 | 259 | 260 | 261 | float 262 | PB_Beam::PRT( void ) const 263 | { 264 | return( Hdr.prt.Value() * ClockCountTime ); 265 | } 266 | 267 | 268 | 269 | int 270 | PB_Beam::Hits( void ) const 271 | { 272 | return( Hdr.hits.Value() ); 273 | } 274 | 275 | 276 | 277 | float 278 | PB_Beam::Delay( void ) const 279 | { 280 | return( Hdr.delay.Value() * ClockCountTime ); 281 | } 282 | 283 | 284 | 285 | const void* 286 | PB_Beam::VelRaw( DataType *type, int *step, float *scale, float *offset ) const 287 | // 288 | // Return raw velocity data for this beam. Since we likely don't have the 289 | // necessary geometry information here, we just return the values scaled 290 | // based on the "normal" Nyquist interval (without bistatic geometry 291 | // adjustment applied) 292 | // 293 | { 294 | int byteoffset; 295 | 296 | if ((byteoffset = OffsetToField( PBFld_V )) >= 0) 297 | { 298 | *type = DataType::INT8; 299 | *step = 1; 300 | *scale = _C_ / (2.0 * Frequency() * PRT() * 255); 301 | *offset = 0.0; 302 | return( (char*)Data + byteoffset ); 303 | } 304 | else 305 | return NULL; 306 | } 307 | 308 | 309 | 310 | const void* 311 | PB_Beam::dBZRaw( DataType *type, int *step, float *scale, float *offset ) const 312 | // 313 | // No reflectivity data in PIRAQ bistatic format 314 | { 315 | return NULL; 316 | } 317 | 318 | 319 | 320 | const void* 321 | PB_Beam::dBmRaw( DataType *type, int *step, float *scale, float *offset ) const 322 | { 323 | int byteoffset; 324 | static char* pwr = 0; 325 | // 326 | // Try for straight power first 327 | // 328 | if ((byteoffset = OffsetToField( PBFld_P )) >= 0) 329 | { 330 | *type = DataType::UINT8; 331 | *step = 1; 332 | *scale = 0.5; 333 | *offset = -127.0; 334 | return( (char*)Data + byteoffset ); 335 | } 336 | // 337 | // Nope. Maybe we have the packed power/NCP (5/3 bits) field 338 | // 339 | else if ((byteoffset = OffsetToField( PBFld_P_NCP )) >= 0) 340 | { 341 | // 342 | // Return the unpacked array 343 | // 344 | *type = DataType::UINT8; 345 | *step = 1; 346 | *scale = 0.5; 347 | *offset = -127.0; 348 | return( UnpackedPwr ); 349 | } 350 | // 351 | // No power data at all... 352 | // 353 | else 354 | return NULL; 355 | } 356 | 357 | 358 | 359 | const void* 360 | PB_Beam::NCPRaw( DataType *type, int *step, float *scale, float *offset ) const 361 | { 362 | int byteoffset; 363 | static char* pwr = 0; 364 | // 365 | // NCP only comes in the packed power/NCP (5/3 bits) field 366 | // 367 | if ((byteoffset = OffsetToField( PBFld_P_NCP )) >= 0) 368 | { 369 | // 370 | // Return the unpacked array 371 | // 372 | *type = DataType::UINT8; 373 | *step = 1; 374 | *scale = 1.0 / 255.0; 375 | *offset = 0.0; 376 | return( UnpackedNCP ); 377 | } 378 | // 379 | // No NCP at all... 380 | // 381 | else 382 | return NULL; 383 | } 384 | 385 | 386 | 387 | const char* 388 | PB_Beam::Info( void ) const 389 | // 390 | // Return a string containing info useful for setting up and syncing a 391 | // bistatic site 392 | // 393 | { 394 | static char info[256]; 395 | char flds[16]; 396 | unsigned char format = Hdr.format.Value(); 397 | 398 | flds[0] = '\0'; 399 | 400 | for (int bit = 0; bit < 8; bit++) 401 | { 402 | if (format & (1 << bit)) 403 | { 404 | if (strlen( flds ) > 0) 405 | strcat( flds, "," ); 406 | strcat( flds, PBFormatInfo[bit].name.c_str() ); 407 | } 408 | } 409 | 410 | sprintf( info, "Flds: %s Delay: %d Rec: %s", flds, Hdr.delay.Value(), 411 | (Hdr.flag.Value() & 0x20) ? "ON" : "OFF" ); 412 | 413 | return info; 414 | } 415 | 416 | 417 | 418 | void 419 | PB_Beam::SyncData( int* pwr, int *vel ) 420 | // 421 | // Return four-bit power and velocity from the first eight gates (returned 422 | // as ints), for verification of proper sync. Power values will range 423 | // from 0 to 15 and velocities will range from -8 to 7. 424 | // 425 | { 426 | unsigned long pwrdata = Hdr.power.Value(); 427 | int g; 428 | 429 | for (g = 0; g < 8; g++) 430 | pwr[g] = (pwrdata >> (4 * g)) & 0xf; 431 | 432 | unsigned long veldata = Hdr.velocity.Value(); 433 | 434 | for (g = 0; g < 8; g ++) 435 | { 436 | vel[g] = (veldata >> (4 * g)) & 0xf; 437 | if (vel[g] > 7) 438 | vel[g] -= 16; 439 | } 440 | } 441 | 442 | 443 | 444 | int 445 | PB_Beam::OffsetToField( PBF_BitID id ) const 446 | { 447 | unsigned char format = Hdr.format.Value(); 448 | int offset = 0; 449 | // 450 | // Verify that the field in question is actually being recorded. 451 | // Return -1 if not. 452 | // 453 | if (! (format & (1 << id))) 454 | return( -1 ); 455 | // 456 | // Loop through the fields that may appear before this one, adding 457 | // appropriately to our offset for each field being recorded. 458 | // 459 | for (int i = 0; i < id; i++) 460 | { 461 | if (format & (1 << i)) 462 | { 463 | int nbytes = Gates() * PBFormatInfo[i].bytes_per_gate; 464 | if (nbytes) 465 | offset += nbytes; 466 | else 467 | { 468 | fprintf( stderr, "PB_Beam: Unexpected bit %d set in format!\n", 469 | i ); 470 | exit( 1 ); 471 | } 472 | } 473 | } 474 | 475 | return( offset ); 476 | } 477 | 478 | 479 | void 480 | PB_Beam::UnpackP_NCP( void ) 481 | // 482 | // Unpack the packed power/NCP field (power is lower 5 bits; NCP is upper 3) 483 | // 484 | { 485 | int byteoffset = OffsetToField( PBFld_P_NCP ); 486 | 487 | if (byteoffset < 0) 488 | return; 489 | // 490 | // Power: lower 5 bits 491 | // 492 | UnpackedPwr = new char[Gates()]; 493 | memmove( UnpackedPwr, (char*)Data + byteoffset, Gates() ); 494 | for (int g = 0; g < Gates(); g++) 495 | UnpackedPwr[g] &= 0xf7; 496 | // 497 | // NCP: upper 3 bits 498 | // 499 | UnpackedNCP = new char[Gates()]; 500 | memmove( UnpackedNCP, (char*)Data + byteoffset, Gates() ); 501 | for (int g = 0; g < Gates(); g++) 502 | UnpackedNCP[g] <<= 5; 503 | } 504 | -------------------------------------------------------------------------------- /VIRAQ_Beam.cc: -------------------------------------------------------------------------------- 1 | // VIRAQ_Beam.cc 2 | // This is the form of the PIRAQ bistatic beam 3 | // 4 | // 5 | // Copyright © 1998 Binet Incorporated 6 | // Copyright © 1998 University Corporation for Atmospheric Research 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | 22 | # include 23 | # include 24 | # include 25 | # include 26 | # include 27 | # include 28 | 29 | # include "VIRAQ_Beam.hh" 30 | extern "C" 31 | { 32 | # include "globals.h" 33 | } 34 | 35 | 36 | // 37 | // VIRAQ beams 38 | // 39 | 40 | // 41 | // Keep around the most recent radar header (This will break when somebody 42 | // starts having more than one VIRAQ source, since we really need to have 43 | // the last radar header for each incoming fd. Fix it later...) 44 | // 45 | static VIRAQ_RHdr LastRHdr; 46 | static int HaveRHdr = 0; 47 | 48 | // 49 | // speed of light 50 | // 51 | const double _C_ = 2.998e8; 52 | 53 | 54 | 55 | VIRAQ_Beam::VIRAQ_Beam( char* inbuf, int& inbuflen, const Receiver* rcvr ) 56 | // 57 | // Construct a VIRAQ_Beam from the given buffer. Upon return, any data we 58 | // have used or skipped is removed from the buffer, with the remainder 59 | // shifted to the head of the buffer. The inbuflen is adjusted 60 | // accordingly. 61 | // 62 | { 63 | int beamlen = inbuflen; // until we know the real length 64 | int nskipped = 0; 65 | // 66 | // Set our data pointers to null until we have a good beam 67 | // 68 | data = 0; 69 | productdata = 0; 70 | // 71 | // Stash the pointer to our receiver 72 | // 73 | MyReceiver = rcvr; 74 | // 75 | // If our partial beam does not begin with 'DWEL' or 'RHDR', we've got 76 | // to look for one of them. 77 | // 78 | if (inbuflen >= 4 && strncmp( inbuf, "DWEL", 4 ) && 79 | strncmp( inbuf, "RHDR", 4)) 80 | { 81 | // 82 | // We need to look for one of the magic cookies somewhere within 83 | // the buffer. We don't check the last three bytes, since the 84 | // cookies are four bytes long. If we find one, shift so that it's 85 | // at the beginning of inbuf, otherwise just move the last three 86 | // bytes to the beginning of inbuf. 87 | // 88 | char *c = inbuf + 1; 89 | while (1) 90 | { 91 | int remainder = inbuf + inbuflen - c; 92 | char* nextd = (char*) memchr( c, 'D', remainder ); 93 | char* nextr = (char*) memchr( c, 'R', remainder ); 94 | 95 | if (! nextd && ! nextr) 96 | { 97 | c = inbuf + inbuflen - 3; 98 | break; 99 | } 100 | 101 | if (nextd && (! nextr || (nextd < nextr))) 102 | { 103 | c = nextd; 104 | if (! strncmp( c, "DWEL", 4 )) 105 | break; 106 | } 107 | else 108 | { 109 | c = nextr; 110 | if (! strncmp( c, "RHDR", 4 )) 111 | break; 112 | } 113 | 114 | c++; 115 | } 116 | 117 | inbuflen = inbuf + inbuflen - c; 118 | nskipped += c - inbuf; 119 | memmove( inbuf, c, inbuflen ); 120 | } 121 | // 122 | // If we're getting a DWEL and have a full VIRAQ_Hdr worth of stuff, 123 | // figure out our true beam length 124 | // 125 | if (inbuf[0] == 'D' && inbuflen >= VIRAQ_HdrLen) 126 | beamlen = ((VIRAQ_Hdr*)inbuf)->recordlen.Value(); 127 | // 128 | // Otherwise, if we're getting an RHDR, the length we're expecting 129 | // is just VIRAQ_RhdrLen 130 | // 131 | else if (inbuf[0] == 'R') 132 | beamlen = VIRAQ_RHdrLen; 133 | // 134 | // If we don't have a full beam or VIRAQ_RHdr, just return now 135 | // 136 | if (inbuflen < beamlen) 137 | return; 138 | // 139 | // If we get here, we should have a complete dwell or VIRAQ_RHdr in our 140 | // beam-in-progress buffer. 141 | // 142 | // Report on how much stuff we skipped to get here. 143 | // 144 | if (nskipped) 145 | fprintf( stderr, "Skipped %d to find %s\n", nskipped, 146 | inbuf[0] == 'D' ? "DWEL" : "RHDR" ); 147 | // 148 | // If we have a VIRAQ_RHdr, just stash it 149 | // 150 | if (inbuf[0] == 'R') 151 | { 152 | memmove( (void*)&LastRHdr, inbuf, VIRAQ_RHdrLen ); 153 | HaveRHdr = 1; 154 | } 155 | // 156 | // Otherwise we have a dwell. 157 | // 158 | else 159 | { 160 | // 161 | // Copy the beginning of our beam-in-progress buffer into our header. 162 | // 163 | hdr = *(VIRAQ_Hdr*)inbuf; 164 | // 165 | // Allocate data space, and copy the data over from the beam-in-progress 166 | // buffer. 167 | // 168 | int datalen = beamlen - VIRAQ_HdrLen; 169 | 170 | data = new char[datalen]; 171 | memmove( data, inbuf + VIRAQ_HdrLen, datalen ); 172 | // 173 | // Copy the latest radar header 174 | // 175 | static int norhdr_count = 0; 176 | 177 | if (HaveRHdr) 178 | rhdr = LastRHdr; 179 | else 180 | { 181 | if (! norhdr_count++) 182 | fprintf( stderr, "VIRAQ_Beam: No RHDR yet\n" ); 183 | else if (! (norhdr_count % 100)) 184 | fprintf( stderr, "VIRAQ_Beam: Still no RHDR...\n" ); 185 | // 186 | // If we don't have a radar header, get rid of our data to 187 | // mark ourselves as not being OK. 188 | // 189 | delete[] data; 190 | data = NULL; 191 | } 192 | } 193 | // 194 | // Calculate and stash our data products 195 | // 196 | if (data) 197 | CalculateProducts(); 198 | // 199 | // Move any remaining data in the beam-in-progress to the head of the line. 200 | // 201 | memmove( inbuf, inbuf + beamlen, inbuflen - beamlen ); 202 | inbuflen -= beamlen; 203 | // 204 | // We're done! 205 | // 206 | return; 207 | } 208 | 209 | 210 | 211 | int 212 | VIRAQ_Beam::OK( void ) const 213 | { 214 | // 215 | // We consider ourselves OK if we have a real pointer to some data 216 | // 217 | return( data != NULL ); 218 | } 219 | 220 | 221 | 222 | double 223 | VIRAQ_Beam::Time( void ) const 224 | { 225 | return (hdr.time.Value() + 0.0001 * hdr.subsec.Value()); 226 | } 227 | 228 | 229 | 230 | int 231 | VIRAQ_Beam::Gates( void ) const 232 | { 233 | return hdr.gates.Value(); 234 | } 235 | 236 | 237 | 238 | float 239 | VIRAQ_Beam::RcvrPulseWidth( void ) const 240 | { 241 | return hdr.rcvr_pulsewidth.Value(); 242 | } 243 | 244 | 245 | 246 | float 247 | VIRAQ_Beam::Azimuth( void ) const 248 | { 249 | return hdr.az.Value(); 250 | } 251 | 252 | 253 | 254 | 255 | float 256 | VIRAQ_Beam::Elevation( void ) const 257 | { 258 | return hdr.el.Value(); 259 | } 260 | 261 | 262 | 263 | float 264 | VIRAQ_Beam::FixedAngle( void ) const 265 | { 266 | return hdr.fxd_angle.Value(); 267 | } 268 | 269 | 270 | 271 | float 272 | VIRAQ_Beam::Frequency( void ) const 273 | { 274 | return rhdr.frequency.Value(); 275 | } 276 | 277 | 278 | 279 | float 280 | VIRAQ_Beam::PRT( void ) const 281 | { 282 | return hdr.prt.Value(); 283 | } 284 | 285 | 286 | 287 | int 288 | VIRAQ_Beam::Hits( void ) const 289 | { 290 | return hdr.hits.Value(); 291 | } 292 | 293 | 294 | 295 | float 296 | VIRAQ_Beam::Delay( void ) const 297 | { 298 | return 0.0; // for now... 299 | } 300 | 301 | 302 | 303 | float 304 | VIRAQ_Beam::RadarLat( void ) const 305 | { 306 | return hdr.radar_latitude.Value(); 307 | } 308 | 309 | 310 | 311 | float 312 | VIRAQ_Beam::RadarLon( void ) const 313 | { 314 | return hdr.radar_longitude.Value(); 315 | } 316 | 317 | 318 | 319 | float 320 | VIRAQ_Beam::RadarAlt( void ) const 321 | { 322 | return hdr.radar_altitude.Value(); 323 | } 324 | 325 | 326 | 327 | int 328 | VIRAQ_Beam::VolNum( void ) const 329 | { 330 | return hdr.vol_num.Value(); 331 | } 332 | 333 | 334 | 335 | int 336 | VIRAQ_Beam::SweepNum( void ) const 337 | { 338 | return hdr.scan_num.Value(); 339 | } 340 | 341 | 342 | 343 | const char* 344 | VIRAQ_Beam::ScanType( void ) const 345 | { 346 | switch (hdr.scan_type.Value() ) 347 | { 348 | case 0: 349 | return "CAL"; 350 | case 1: 351 | return "PPI"; 352 | case 2: 353 | return "COP"; 354 | case 3: 355 | return "RHI"; 356 | case 4: 357 | return "VER"; 358 | case 5: 359 | return "TAR"; 360 | case 6: 361 | return "MAN"; 362 | case 7: 363 | return "IDL"; 364 | case 8: 365 | return "SUR"; 366 | case 9: 367 | return "AIR"; 368 | case 10: 369 | return "HOR"; 370 | default: 371 | return "UNK"; 372 | } 373 | } 374 | 375 | 376 | 377 | void 378 | VIRAQ_Beam::CalculateProducts( void ) 379 | { 380 | productdata = new float[16 * Gates()]; 381 | 382 | RADAR* radar = (RADAR*)&rhdr; 383 | 384 | DWELL* dwell = new DWELL; 385 | memmove( dwell, &hdr, sizeof( hdr ) ); 386 | memmove( (char*)(dwell) + sizeof( hdr ), data, 387 | hdr.recordlen.Value() - sizeof( hdr ) ); 388 | // 389 | // products() returns 16 values per gate: 390 | // 391 | // 0: H velocity, m/s 392 | // 1: H power, dBm 393 | // 2: NCP 394 | // 3: spectrum width, m/s 395 | // 4: H reflectivity, dBZ 396 | // ... 397 | // 398 | # if (__BYTE_ORDER == __LITTLE_ENDIAN) 399 | products( dwell, radar, productdata ); 400 | # else 401 | # error "I use products.c, which only works on little-endian systems" 402 | # endif 403 | 404 | delete[] dwell; 405 | } 406 | 407 | 408 | 409 | const void* 410 | VIRAQ_Beam::VelRaw( DataType *type, int *step, float *scale, 411 | float *offset ) const 412 | { 413 | *type = DataType::FLOAT; 414 | *scale = 1.0; 415 | *offset = 0.0; 416 | 417 | switch (hdr.dataformat.Value()) 418 | { 419 | case DATA_POL3: 420 | case DATA_SIMPLEPP: 421 | case DATA_MAXPOL: 422 | *step = 16 * sizeof( float ); 423 | return productdata; 424 | default: 425 | fprintf( stderr, "VIRAQ_Beam::VelRaw can't handle format %d\n", 426 | hdr.dataformat.Value()); 427 | return NULL; 428 | } 429 | } 430 | 431 | 432 | 433 | 434 | const void* 435 | VIRAQ_Beam::dBZRaw( DataType *type, int *step, float *scale, 436 | float *offset ) const 437 | { 438 | *type = DataType::FLOAT; 439 | *scale = 1.0; 440 | *offset = 0.0; 441 | 442 | switch (hdr.dataformat.Value()) 443 | { 444 | case DATA_POL3: 445 | case DATA_SIMPLEPP: 446 | case DATA_MAXPOL: 447 | *step = 16 * sizeof( float ); 448 | return productdata + 4; 449 | default: 450 | fprintf( stderr, "VIRAQ_Beam::dBZRaw can't handle format %d\n", 451 | hdr.dataformat.Value()); 452 | return NULL; 453 | } 454 | } 455 | 456 | 457 | 458 | 459 | const void* 460 | VIRAQ_Beam::dBmRaw( DataType *type, int *step, float *scale, 461 | float *offset ) const 462 | { 463 | *type = DataType::FLOAT; 464 | *scale = 1.0; 465 | *offset = 0.0; 466 | 467 | switch (hdr.dataformat.Value()) 468 | { 469 | case DATA_POL3: 470 | case DATA_SIMPLEPP: 471 | case DATA_MAXPOL: 472 | *step = 16 * sizeof( float ); 473 | return productdata + 1; 474 | default: 475 | fprintf( stderr, "VIRAQ_Beam::dBmRaw can't handle format %d\n", 476 | hdr.dataformat.Value()); 477 | return NULL; 478 | } 479 | } 480 | 481 | 482 | 483 | 484 | const void* 485 | VIRAQ_Beam::NCPRaw( DataType *type, int *step, float *scale, 486 | float *offset ) const 487 | { 488 | *type = DataType::FLOAT; 489 | *scale = 1.0; 490 | *offset = 0.0; 491 | 492 | switch (hdr.dataformat.Value()) 493 | { 494 | case DATA_POL3: 495 | case DATA_SIMPLEPP: 496 | case DATA_MAXPOL: 497 | *step = 16 * sizeof( float ); 498 | return productdata + 2; 499 | default: 500 | fprintf( stderr, "VIRAQ_Beam::NCPRaw can't handle format %d\n", 501 | hdr.dataformat.Value()); 502 | return NULL; 503 | } 504 | } 505 | 506 | 507 | const void* 508 | VIRAQ_Beam::XmtrInfoPacket( int* len ) 509 | // 510 | // S-Pol does not generate phase/info packets, so we have to create them 511 | // ourselves... The packet returned is valid until the next call to 512 | // this method. 513 | // 514 | { 515 | typedef struct _infoPkt 516 | { 517 | unsigned long long pulsenum; 518 | unsigned short hits; 519 | unsigned short sync; 520 | unsigned short az; 521 | unsigned short el; 522 | unsigned short prt; 523 | unsigned char freq; 524 | char spare; 525 | } infoPkt; 526 | 527 | static infoPkt packet; 528 | 529 | packet.pulsenum = 0; // unused for klystron systems 530 | packet.hits = Hits(); 531 | packet.sync = 0; // unused for klystron systems 532 | packet.az = (unsigned short)(Azimuth() * 65536 / 360.0); 533 | packet.el = (unsigned short)(Elevation() * 65536 / 360.0); 534 | packet.prt = (unsigned short)(PRT() * 8.0e6 + 0.5); 535 | packet.freq = 0; // unused for klystron systems 536 | 537 | *len = sizeof( infoPkt ); 538 | return &packet; 539 | } 540 | -------------------------------------------------------------------------------- /MergedBeam.cc: -------------------------------------------------------------------------------- 1 | // MergedBeam.cc 2 | // This is the form of a merged bistatic beam 3 | // 4 | // Copyright © 2000 Binet Incorporated 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | 21 | # include 22 | # include 23 | # include 24 | # include "MergedBeam.hh" 25 | # include "Receiver.hh" 26 | 27 | inline float RAD_TO_DEG( float x ) { return( 180.0 * x / M_PI ); } 28 | inline float DEG_TO_RAD( float x ) { return( M_PI * x / 180.0 ); } 29 | const float _C_ = 2.99792458e8; // speed of light, m/s 30 | 31 | 32 | 33 | MergedBeam::MergedBeam( const Beam* beams[], int nbeams, float ncp_thresh ) 34 | // 35 | // Instantiate a "merged" beam from the given beams. The first beam in 36 | // the list is assumed to be that from the transmitting site, and is used 37 | // for values that must be common among the beams, e.g., time, azimuth, 38 | // etc. 39 | // 40 | { 41 | NMembers = nbeams; 42 | // 43 | // stash our member beams 44 | // 45 | Members = new Beam*[NMembers]; 46 | memmove( Members, beams, NMembers * sizeof( Members[0] ) ); 47 | // 48 | // save the NCP threshold value 49 | // 50 | NCPThresh = ncp_thresh; 51 | // 52 | // Derive winds 53 | // 54 | DeriveWinds(); 55 | } 56 | 57 | 58 | 59 | MergedBeam::~MergedBeam( void ) 60 | { 61 | delete[] Members; 62 | for (int m = 0; m < NMembers; m++) 63 | { 64 | delete[] U[m]; 65 | delete[] V[m]; 66 | } 67 | 68 | delete[] U; 69 | delete[] V; 70 | delete[] UBest; 71 | delete[] VBest; 72 | } 73 | 74 | 75 | 76 | int 77 | MergedBeam::OK( void ) const 78 | { 79 | // 80 | // Just make sure all our members are OK 81 | // 82 | for (int m = 0; m < NMembers; m++) 83 | { 84 | if (! Members[m]->OK()) 85 | return 0; 86 | } 87 | return 1; 88 | } 89 | 90 | 91 | 92 | int 93 | MergedBeam::UWindData( float* data, int maxlen, float badval, int rcvr ) const 94 | { 95 | // 96 | // Make sure we're given enough space 97 | // 98 | if (maxlen < Gates()) 99 | { 100 | fprintf( stderr, "MergedBeam::UWindData: not enough data space\n" ); 101 | return 0; 102 | } 103 | // 104 | // Copy the data into the user's array and substitute in the user's bad 105 | // value flag 106 | // 107 | memmove( data, U[rcvr], Gates() * sizeof(float) ); 108 | for (int g = 0; g < Gates(); g++) 109 | if (U[rcvr][g] == FBADVAL) 110 | data[g] = badval; 111 | 112 | return 1; 113 | } 114 | 115 | 116 | 117 | int 118 | MergedBeam::VWindData( float* data, int maxlen, float badval, int rcvr ) const 119 | { 120 | // 121 | // Make sure we're given enough space 122 | // 123 | if (maxlen < Gates()) 124 | { 125 | fprintf( stderr, "MergedBeam::VWindData: not enough data space\n" ); 126 | return 0; 127 | } 128 | // 129 | // Copy the data into the user's array and substitute in the user's bad 130 | // value flag 131 | // 132 | memmove( data, V[rcvr], Gates() * sizeof(float) ); 133 | for (int g = 0; g < Gates(); g++) 134 | if (V[rcvr][g] == FBADVAL) 135 | data[g] = badval; 136 | 137 | return 1; 138 | } 139 | 140 | 141 | 142 | int 143 | MergedBeam::UBestData( float* data, int maxlen, float badval ) const 144 | { 145 | // 146 | // Make sure we're given enough space 147 | // 148 | if (maxlen < Gates()) 149 | { 150 | fprintf( stderr, "MergedBeam::UBestData: not enough data space\n" ); 151 | return 0; 152 | } 153 | // 154 | // Copy the data into the user's array and substitute in the user's bad 155 | // value flag 156 | // 157 | memmove( data, UBest, Gates() * sizeof(float) ); 158 | for (int g = 0; g < Gates(); g++) 159 | if (UBest[g] == FBADVAL) 160 | data[g] = badval; 161 | 162 | return 1; 163 | } 164 | 165 | 166 | 167 | int 168 | MergedBeam::VBestData( float* data, int maxlen, float badval ) const 169 | { 170 | // 171 | // Make sure we're given enough space 172 | // 173 | if (maxlen < Gates()) 174 | { 175 | fprintf( stderr, "MergedBeam::VBestData: not enough data space\n" ); 176 | return 0; 177 | } 178 | // 179 | // Copy the data into the user's array and substitute in the user's bad 180 | // value flag 181 | // 182 | memmove( data, VBest, Gates() * sizeof(float) ); 183 | for (int g = 0; g < Gates(); g++) 184 | if (VBest[g] == FBADVAL) 185 | data[g] = badval; 186 | 187 | return 1; 188 | } 189 | 190 | 191 | 192 | void 193 | MergedBeam::RcvrGateAndAz( int x_gate, int rcvr, int *r_gate, float *r_az, 194 | float phi, float sin_phi, float cos_phi ) 195 | // 196 | // Translate the xmitter gate and azimuth into gate and azimuth for 197 | // receiver 'rcvr'. Phi is the angle from the xmitter-to-receiver baseline 198 | // to the beam (range -180 to 180). 199 | // 200 | { 201 | // 202 | // Get the baseline length, then calculate the range from the xmitter and 203 | // from the receiver to the gate. 204 | // 205 | float base = Members[rcvr]->Rcvr()->RangeFromRadar() * 1000.0; // km -> m 206 | 207 | float x_range = (x_gate + 0.5) * (0.5 * _C_ * RcvrPulseWidth( 0 )); 208 | float r_range = sqrt( x_range * x_range + base * base - 209 | 2 * x_range * base * cos_phi ); 210 | // 211 | // We should get the real delay at some point, but for now assume the 212 | // bistatic receivers start sampling 4 gates before the first pulse arrives 213 | // from the transmitter. 214 | // 215 | float delay = (base / _C_) - (4.0 * RcvrPulseWidth( rcvr )); 216 | // 217 | // Get the floating point bistatic receiver distance to the illuminated 218 | // volume, in units of bistatic gates. 219 | // 220 | float r_gate_f = 221 | (x_range + r_range) / (_C_ * RcvrPulseWidth( rcvr )) - 222 | delay / RcvrPulseWidth( rcvr ); 223 | 224 | if (r_gate_f < 0.0 ) 225 | r_gate_f = 0.0; 226 | 227 | *r_gate = (int) r_gate_f; 228 | // 229 | // Finally, the azimuth from the receiver to the gate 230 | // 231 | if (phi < 0.0) 232 | *r_az = Members[rcvr]->Rcvr()->AzFromRadar() + 180.0 + 233 | RAD_TO_DEG( acos( (r_range*r_range + base*base - x_range*x_range) / 234 | (2.0 * r_range * base) ) ); 235 | else 236 | *r_az = Members[rcvr]->Rcvr()->AzFromRadar() + 180.0 - 237 | RAD_TO_DEG( acos( (r_range*r_range + base*base - x_range*x_range) / 238 | (2.0 * r_range * base) ) ); 239 | 240 | if (*r_az < 0.0) 241 | *r_az += 360.0; 242 | else if (*r_az > 360.0) 243 | *r_az -= 360.0; 244 | } 245 | 246 | 247 | 248 | void 249 | MergedBeam::DeriveWinds( void ) 250 | // 251 | // Calculate dual-Doppler u and v given the current beam data. 252 | // If ncp_threshold is > 0.0, only calculate winds for gates where the 253 | // NCP from the bistatic receiver is greater than the given threshold. 254 | // If ncp_threshold is <= 0.0, no thresholding is applied. 255 | // 256 | { 257 | int gate; 258 | // 259 | // allocate per-member u and v data arrays 260 | // 261 | U = new float*[NMembers]; 262 | V = new float*[NMembers]; 263 | for (int m = 0; m < NMembers; m++) 264 | { 265 | if (m) 266 | { 267 | U[m] = new float[Gates()]; 268 | V[m] = new float[Gates()]; 269 | } 270 | else 271 | { 272 | // no u and v for the transmitter paired with itself... 273 | U[0] = V[0] = 0; 274 | } 275 | } 276 | // 277 | // space for best u and v arrays 278 | // 279 | UBest = new float[Gates()]; 280 | VBest = new float[Gates()]; 281 | // 282 | // Transmitter gate length in meters and number of gates 283 | // 284 | float gatelen = 0.5 * _C_ * RcvrPulseWidth( 0 ); 285 | int n_xmtr_gates = Gates( 0 ); 286 | // 287 | // Radial velocity from the transmitter 288 | // 289 | float *xmtr_vel = new float[n_xmtr_gates]; 290 | VelData( xmtr_vel, n_xmtr_gates, FBADVAL, 0 ); 291 | // 292 | // Arrays to keep weighted best winds estimates 293 | // 294 | float* weight = new float[n_xmtr_gates]; 295 | // 296 | // Geometry terms that are constant for the beam 297 | // 298 | float az = Azimuth(); 299 | float cosat = cos( DEG_TO_RAD( az ) ); 300 | float sinat = sin( DEG_TO_RAD( az ) ); 301 | // 302 | // Initialize for best winds calculations 303 | // 304 | for (gate = 0; gate < n_xmtr_gates; gate++) 305 | { 306 | UBest[gate] = VBest[gate] = 0.0; 307 | weight[gate] = 0.0; 308 | } 309 | // 310 | // Do the calculations for each bistatic receiver 311 | // 312 | for (int b = 1; b < NMembers; b++) 313 | { 314 | DataType dt; 315 | int step; 316 | float scale, offset; 317 | int n_rcvr_gates = Gates( b ); 318 | // 319 | // Angle from the radar->receiver baseline to the beam 320 | // 321 | float phi = az - Members[b]->Rcvr()->AzFromRadar(); 322 | if (phi < -180.0) 323 | phi += 360.0; 324 | else if (phi > 180.0) 325 | phi -= 360.0; 326 | 327 | float sin_phi = sin( DEG_TO_RAD( phi ) ); 328 | float cos_phi = cos( DEG_TO_RAD( phi ) ); 329 | // 330 | // Get the (floating-point) velocity and NCP data for this receiver 331 | // 332 | float *rcvr_vel = new float[n_rcvr_gates]; 333 | float *rcvr_ncp = new float[n_rcvr_gates]; 334 | VelData( rcvr_vel, n_rcvr_gates, FBADVAL, b ); 335 | NCPData( rcvr_ncp, n_rcvr_gates, FBADVAL, b ); 336 | // 337 | // For each xmitter gate.. 338 | // 339 | for (gate = 1; gate < n_xmtr_gates; gate++) 340 | { 341 | U[b][gate] = FBADVAL; 342 | V[b][gate] = FBADVAL; 343 | // 344 | // get bistatic receiver gate and az that corresponds to xmitter gate 345 | // 346 | float b_az; 347 | 348 | int b_gate; 349 | 350 | RcvrGateAndAz( gate, b, &b_gate, &b_az, phi, sin_phi, cos_phi ); 351 | // 352 | // Make sure we're in the valid range of gates for this receiver 353 | // (Ignore receiver gates less than 4, since the receivers begin 354 | // sampling 4 gates before the arrival of the transmit pulse.) 355 | // 356 | if (b_gate < 5) 357 | continue; 358 | 359 | if (b_gate > n_rcvr_gates) 360 | { 361 | // 362 | // Fill the rest of the gates with bad values, and we're done 363 | // with this receiver 364 | // 365 | for (; gate < n_xmtr_gates; gate++) 366 | { 367 | U[b][gate] = FBADVAL; 368 | V[b][gate] = FBADVAL; 369 | } 370 | 371 | break; 372 | } 373 | // 374 | // Threshold on NCP if we were given a threshold value > 0.0 375 | // 376 | if (NCPThresh > 0.0 && rcvr_ncp[b_gate] < NCPThresh) 377 | continue; 378 | // 379 | // For each gate, calculate u,v from geometry and 380 | // V(bistatic) and V(xmtr) This formulation follows from 381 | // Wurman, et al., Journal of Applied Meteor. #32, 382 | // December, 1993, p1802-1814. Invert equation #3 383 | // omitting 2nd receiver terms and terms that contain the 384 | // elevation angle of the transmitter 385 | // 386 | 387 | // 388 | // calculate geometry terms, ignoring elevation angle 389 | // 390 | float cosab = cos( DEG_TO_RAD( b_az ) ); 391 | float sinab = sin( DEG_TO_RAD( b_az ) ); 392 | float sumsin = (sinab + sinat); 393 | float sumcos = (cosab + cosat); 394 | float denom = 1.0 / sin( DEG_TO_RAD( az - b_az ) ); 395 | // 396 | // Set vt to transmitter radial velocity at the current 397 | // gate, and vb to the bistatic receiver elliptic-normal velocity 398 | // at the overlapping bistatic gate. 399 | // 400 | // The elliptical correction for bistatic receiver velocities is 401 | // applied here: 402 | // v_actual = v_uncorrected / cos (scattering_angle / 2) 403 | // 404 | float scat_ang = b_az - az; 405 | if (scat_ang < -180.0) 406 | scat_ang += 360.0; 407 | else if (scat_ang > 180.0) 408 | scat_ang -= 360.0; 409 | 410 | float vt = xmtr_vel[gate]; 411 | float vb = rcvr_vel[b_gate] / cos( 0.5 * DEG_TO_RAD( scat_ang ) ); 412 | // 413 | // calculate cartesian dual-Doppler (u,v) velocities 414 | // 415 | float uspd = (-2 * cosat * vb + sumcos * vt) * denom; 416 | float vspd = (2 * sinat * vb - sumsin * vt) * denom; 417 | // 418 | // If the total wind speed is unreasonably large (> VelMax m/s), 419 | // then skip gate 420 | // 421 | if ((uspd * uspd + vspd * vspd) > (VelMax * VelMax)) 422 | { 423 | U[b][gate] = FBADVAL; 424 | V[b][gate] = FBADVAL; 425 | } 426 | // 427 | // Otherwise, stash u and v and calculate weighting factor for use 428 | // in finding best wind 429 | // 430 | else 431 | { 432 | U[b][gate] = uspd; 433 | V[b][gate] = vspd; 434 | // 435 | // Weight this wind (currently using just the sine of the 436 | // scattering angle), and add it into our weighted best wind 437 | // estimate for this gate. 438 | // 439 | float bweight = sin( DEG_TO_RAD( scat_ang )); 440 | 441 | UBest[gate] += uspd * bweight; 442 | VBest[gate] += vspd * bweight; 443 | weight[gate] += bweight; 444 | } 445 | 446 | } 447 | 448 | delete[] rcvr_vel; 449 | delete[] rcvr_ncp; 450 | } 451 | // 452 | // Divide out the weight from our weighted best wind estimates 453 | // 454 | for (gate = 1; gate < n_xmtr_gates; gate++) 455 | { 456 | if (weight[gate]) 457 | { 458 | UBest[gate] /= weight[gate]; 459 | VBest[gate] /= weight[gate]; 460 | } 461 | else 462 | { 463 | UBest[gate] = VBest[gate] = FBADVAL; 464 | } 465 | } 466 | 467 | delete[] weight; 468 | delete[] xmtr_vel; 469 | } 470 | -------------------------------------------------------------------------------- /depcomp: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # depcomp - compile a program generating dependencies as side-effects 4 | # Copyright 1999, 2000 Free Software Foundation, Inc. 5 | 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2, or (at your option) 9 | # any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 | # 02111-1307, USA. 20 | 21 | # As a special exception to the GNU General Public License, if you 22 | # distribute this file as part of a program that contains a 23 | # configuration script generated by Autoconf, you may include it under 24 | # the same distribution terms that you use for the rest of that program. 25 | 26 | # Originally written by Alexandre Oliva . 27 | 28 | if test -z "$depmode" || test -z "$source" || test -z "$object"; then 29 | echo "depcomp: Variables source, object and depmode must be set" 1>&2 30 | exit 1 31 | fi 32 | # `libtool' can also be set to `yes' or `no'. 33 | 34 | if test -z "$depfile"; then 35 | base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` 36 | dir=`echo "$object" | sed 's,/.*$,/,'` 37 | if test "$dir" = "$object"; then 38 | dir= 39 | fi 40 | # FIXME: should be _deps on DOS. 41 | depfile="$dir.deps/$base" 42 | fi 43 | 44 | tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} 45 | 46 | rm -f "$tmpdepfile" 47 | 48 | # Some modes work just like other modes, but use different flags. We 49 | # parameterize here, but still list the modes in the big case below, 50 | # to make depend.m4 easier to write. Note that we *cannot* use a case 51 | # here, because this file can only contain one case statement. 52 | if test "$depmode" = hp; then 53 | # HP compiler uses -M and no extra arg. 54 | gccflag=-M 55 | depmode=gcc 56 | fi 57 | 58 | if test "$depmode" = dashXmstdout; then 59 | # This is just like dashmstdout with a different argument. 60 | dashmflag=-xM 61 | depmode=dashmstdout 62 | fi 63 | 64 | case "$depmode" in 65 | gcc3) 66 | ## gcc 3 implements dependency tracking that does exactly what 67 | ## we want. Yay! Note: for some reason libtool 1.4 doesn't like 68 | ## it if -MD -MP comes after the -MF stuff. Hmm. 69 | "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" 70 | stat=$? 71 | if test $stat -eq 0; then : 72 | else 73 | rm -f "$tmpdepfile" 74 | exit $stat 75 | fi 76 | mv "$tmpdepfile" "$depfile" 77 | ;; 78 | 79 | gcc) 80 | ## There are various ways to get dependency output from gcc. Here's 81 | ## why we pick this rather obscure method: 82 | ## - Don't want to use -MD because we'd like the dependencies to end 83 | ## up in a subdir. Having to rename by hand is ugly. 84 | ## (We might end up doing this anyway to support other compilers.) 85 | ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like 86 | ## -MM, not -M (despite what the docs say). 87 | ## - Using -M directly means running the compiler twice (even worse 88 | ## than renaming). 89 | if test -z "$gccflag"; then 90 | gccflag=-MD, 91 | fi 92 | "$@" -Wp,"$gccflag$tmpdepfile" 93 | stat=$? 94 | if test $stat -eq 0; then : 95 | else 96 | rm -f "$tmpdepfile" 97 | exit $stat 98 | fi 99 | rm -f "$depfile" 100 | echo "$object : \\" > "$depfile" 101 | alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 102 | ## The second -e expression handles DOS-style file names with drive letters. 103 | sed -e 's/^[^:]*: / /' \ 104 | -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" 105 | ## This next piece of magic avoids the `deleted header file' problem. 106 | ## The problem is that when a header file which appears in a .P file 107 | ## is deleted, the dependency causes make to die (because there is 108 | ## typically no way to rebuild the header). We avoid this by adding 109 | ## dummy dependencies for each header file. Too bad gcc doesn't do 110 | ## this for us directly. 111 | tr ' ' ' 112 | ' < "$tmpdepfile" | 113 | ## Some versions of gcc put a space before the `:'. On the theory 114 | ## that the space means something, we add a space to the output as 115 | ## well. 116 | ## Some versions of the HPUX 10.20 sed can't process this invocation 117 | ## correctly. Breaking it into two sed invocations is a workaround. 118 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 119 | rm -f "$tmpdepfile" 120 | ;; 121 | 122 | hp) 123 | # This case exists only to let depend.m4 do its work. It works by 124 | # looking at the text of this script. This case will never be run, 125 | # since it is checked for above. 126 | exit 1 127 | ;; 128 | 129 | sgi) 130 | if test "$libtool" = yes; then 131 | "$@" "-Wp,-MDupdate,$tmpdepfile" 132 | else 133 | "$@" -MDupdate "$tmpdepfile" 134 | fi 135 | stat=$? 136 | if test $stat -eq 0; then : 137 | else 138 | rm -f "$tmpdepfile" 139 | exit $stat 140 | fi 141 | rm -f "$depfile" 142 | 143 | if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files 144 | echo "$object : \\" > "$depfile" 145 | 146 | # Clip off the initial element (the dependent). Don't try to be 147 | # clever and replace this with sed code, as IRIX sed won't handle 148 | # lines with more than a fixed number of characters (4096 in 149 | # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; 150 | # the IRIX cc adds comments like `#:fec' to the end of the 151 | # dependency line. 152 | tr ' ' ' 153 | ' < "$tmpdepfile" \ 154 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ 155 | tr ' 156 | ' ' ' >> $depfile 157 | echo >> $depfile 158 | 159 | # The second pass generates a dummy entry for each header file. 160 | tr ' ' ' 161 | ' < "$tmpdepfile" \ 162 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ 163 | >> $depfile 164 | else 165 | # The sourcefile does not contain any dependencies, so just 166 | # store a dummy comment line, to avoid errors with the Makefile 167 | # "include basename.Plo" scheme. 168 | echo "#dummy" > "$depfile" 169 | fi 170 | rm -f "$tmpdepfile" 171 | ;; 172 | 173 | aix) 174 | # The C for AIX Compiler uses -M and outputs the dependencies 175 | # in a .u file. This file always lives in the current directory. 176 | # Also, the AIX compiler puts `$object:' at the start of each line; 177 | # $object doesn't have directory information. 178 | stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` 179 | tmpdepfile="$stripped.u" 180 | outname="$stripped.o" 181 | if test "$libtool" = yes; then 182 | "$@" -Wc,-M 183 | else 184 | "$@" -M 185 | fi 186 | 187 | stat=$? 188 | if test $stat -eq 0; then : 189 | else 190 | rm -f "$tmpdepfile" 191 | exit $stat 192 | fi 193 | 194 | if test -f "$tmpdepfile"; then 195 | # Each line is of the form `foo.o: dependent.h'. 196 | # Do two passes, one to just change these to 197 | # `$object: dependent.h' and one to simply `dependent.h:'. 198 | sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" 199 | sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" 200 | else 201 | # The sourcefile does not contain any dependencies, so just 202 | # store a dummy comment line, to avoid errors with the Makefile 203 | # "include basename.Plo" scheme. 204 | echo "#dummy" > "$depfile" 205 | fi 206 | rm -f "$tmpdepfile" 207 | ;; 208 | 209 | tru64) 210 | # The Tru64 compiler uses -MD to generate dependencies as a side 211 | # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. 212 | # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put 213 | # dependencies in `foo.d' instead, so we check for that too. 214 | # Subdirectories are respected. 215 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 216 | test "x$dir" = "x$object" && dir= 217 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 218 | 219 | if test "$libtool" = yes; then 220 | tmpdepfile1="$dir.libs/$base.lo.d" 221 | tmpdepfile2="$dir.libs/$base.d" 222 | "$@" -Wc,-MD 223 | else 224 | tmpdepfile1="$dir$base.o.d" 225 | tmpdepfile2="$dir$base.d" 226 | "$@" -MD 227 | fi 228 | 229 | stat=$? 230 | if test $stat -eq 0; then : 231 | else 232 | rm -f "$tmpdepfile1" "$tmpdepfile2" 233 | exit $stat 234 | fi 235 | 236 | if test -f "$tmpdepfile1"; then 237 | tmpdepfile="$tmpdepfile1" 238 | else 239 | tmpdepfile="$tmpdepfile2" 240 | fi 241 | if test -f "$tmpdepfile"; then 242 | sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" 243 | # That's a space and a tab in the []. 244 | sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" 245 | else 246 | echo "#dummy" > "$depfile" 247 | fi 248 | rm -f "$tmpdepfile" 249 | ;; 250 | 251 | #nosideeffect) 252 | # This comment above is used by automake to tell side-effect 253 | # dependency tracking mechanisms from slower ones. 254 | 255 | dashmstdout) 256 | # Important note: in order to support this mode, a compiler *must* 257 | # always write the proprocessed file to stdout, regardless of -o. 258 | "$@" || exit $? 259 | 260 | # Remove the call to Libtool. 261 | if test "$libtool" = yes; then 262 | while test $1 != '--mode=compile'; do 263 | shift 264 | done 265 | shift 266 | fi 267 | 268 | # Remove `-o $object'. We will use -o /dev/null later, 269 | # however we can't do the remplacement now because 270 | # `-o $object' might simply not be used 271 | IFS=" " 272 | for arg 273 | do 274 | case $arg in 275 | -o) 276 | shift 277 | ;; 278 | $object) 279 | shift 280 | ;; 281 | *) 282 | set fnord "$@" "$arg" 283 | shift # fnord 284 | shift # $arg 285 | ;; 286 | esac 287 | done 288 | 289 | test -z "$dashmflag" && dashmflag=-M 290 | "$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" 291 | rm -f "$depfile" 292 | cat < "$tmpdepfile" > "$depfile" 293 | tr ' ' ' 294 | ' < "$tmpdepfile" | \ 295 | ## Some versions of the HPUX 10.20 sed can't process this invocation 296 | ## correctly. Breaking it into two sed invocations is a workaround. 297 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 298 | rm -f "$tmpdepfile" 299 | ;; 300 | 301 | dashXmstdout) 302 | # This case only exists to satisfy depend.m4. It is never actually 303 | # run, as this mode is specially recognized in the preamble. 304 | exit 1 305 | ;; 306 | 307 | makedepend) 308 | "$@" || exit $? 309 | # X makedepend 310 | shift 311 | cleared=no 312 | for arg in "$@"; do 313 | case $cleared in 314 | no) 315 | set ""; shift 316 | cleared=yes ;; 317 | esac 318 | case "$arg" in 319 | -D*|-I*) 320 | set fnord "$@" "$arg"; shift ;; 321 | -*) 322 | ;; 323 | *) 324 | set fnord "$@" "$arg"; shift ;; 325 | esac 326 | done 327 | obj_suffix="`echo $object | sed 's/^.*\././'`" 328 | touch "$tmpdepfile" 329 | ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" 330 | rm -f "$depfile" 331 | cat < "$tmpdepfile" > "$depfile" 332 | sed '1,2d' "$tmpdepfile" | tr ' ' ' 333 | ' | \ 334 | ## Some versions of the HPUX 10.20 sed can't process this invocation 335 | ## correctly. Breaking it into two sed invocations is a workaround. 336 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 337 | rm -f "$tmpdepfile" "$tmpdepfile".bak 338 | ;; 339 | 340 | cpp) 341 | # Important note: in order to support this mode, a compiler *must* 342 | # always write the proprocessed file to stdout. 343 | "$@" || exit $? 344 | 345 | # Remove the call to Libtool. 346 | if test "$libtool" = yes; then 347 | while test $1 != '--mode=compile'; do 348 | shift 349 | done 350 | shift 351 | fi 352 | 353 | # Remove `-o $object'. 354 | IFS=" " 355 | for arg 356 | do 357 | case $arg in 358 | -o) 359 | shift 360 | ;; 361 | $object) 362 | shift 363 | ;; 364 | *) 365 | set fnord "$@" "$arg" 366 | shift # fnord 367 | shift # $arg 368 | ;; 369 | esac 370 | done 371 | 372 | "$@" -E | 373 | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | 374 | sed '$ s: \\$::' > "$tmpdepfile" 375 | rm -f "$depfile" 376 | echo "$object : \\" > "$depfile" 377 | cat < "$tmpdepfile" >> "$depfile" 378 | sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" 379 | rm -f "$tmpdepfile" 380 | ;; 381 | 382 | msvisualcpp) 383 | # Important note: in order to support this mode, a compiler *must* 384 | # always write the proprocessed file to stdout, regardless of -o, 385 | # because we must use -o when running libtool. 386 | "$@" || exit $? 387 | IFS=" " 388 | for arg 389 | do 390 | case "$arg" in 391 | "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") 392 | set fnord "$@" 393 | shift 394 | shift 395 | ;; 396 | *) 397 | set fnord "$@" "$arg" 398 | shift 399 | shift 400 | ;; 401 | esac 402 | done 403 | "$@" -E | 404 | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" 405 | rm -f "$depfile" 406 | echo "$object : \\" > "$depfile" 407 | . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" 408 | echo " " >> "$depfile" 409 | . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" 410 | rm -f "$tmpdepfile" 411 | ;; 412 | 413 | none) 414 | exec "$@" 415 | ;; 416 | 417 | *) 418 | echo "Unknown depmode $depmode" 1>&2 419 | exit 1 420 | ;; 421 | esac 422 | 423 | exit 0 424 | -------------------------------------------------------------------------------- /BistaticHub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # BistaticHub.py 4 | # This is the GUI front-end used to run the BistaticHub program for collecting 5 | # and processing bistatic radar data 6 | # 7 | # Copyright © 1999 Binet Incorporated 8 | # Copyright © 1999 University Corporation for Atmospheric Research 9 | # 10 | # Licensed under the Apache License, Version 2.0 (the "License"); 11 | # you may not use this file except in compliance with the License. 12 | # You may obtain a copy of the License at 13 | # 14 | # 15 | # http:#www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the License is distributed on an "AS IS" BASIS, 20 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | # See the License for the specific language governing permissions and 22 | # limitations under the License. 23 | 24 | import os 25 | import sys 26 | import re 27 | import signal 28 | import fcntl 29 | import time 30 | import tkinter 31 | from tkinter.simpledialog import Dialog 32 | from tkinter import Frame, Label, Button, Text, Scrollbar, Pack, IntVar, \ 33 | Radiobutton, Entry, StringVar, Menu, Menubutton 34 | 35 | class BistaticHub( Frame ): 36 | def __init__( self, master=None ): 37 | Frame.__init__( self, master ) 38 | self.debuglevel = 0 39 | self.ncpthresh = -1.0 40 | self.winfo_toplevel().title("Bistatic Hub Control and Status") 41 | self.createWidgets() 42 | Pack.config( self ) 43 | self.rcvrs = {} 44 | 45 | signal.signal( signal.SIGCHLD, self.childDied ) 46 | signal.signal( signal.SIGTERM, self.sigExit ) 47 | signal.signal( signal.SIGINT, self.sigExit ) 48 | signal.signal( signal.SIGSEGV, self.sigExit ) 49 | signal.signal( signal.SIGQUIT, self.sigExit ) 50 | self.startclient() 51 | self.tk.createfilehandler( self.from_client.fileno(), tkinter.READABLE, self.incoming ) 52 | 53 | def createWidgets( self ): 54 | # 55 | # bottom buttons 56 | # 57 | buttonframe = Frame( self ) 58 | buttonframe.pack( side=tkinter.BOTTOM, fill=tkinter.X ) 59 | 60 | self.recbutton = Button( buttonframe, text="Hub Recording is: unknown", 61 | command=self.toggleRecording ) 62 | self.recbutton.pack( side=tkinter.LEFT ) 63 | 64 | self.debugbutton = Button( buttonframe, text="Debug Level: unknown", 65 | command=self.debugDialog ) 66 | self.debugbutton.pack( side=tkinter.LEFT ) 67 | 68 | self.ncpbutton = Button( buttonframe, text="NCP threshold: unknown", 69 | command=self.ncpDialog ) 70 | self.ncpbutton.pack( side=tkinter.LEFT ) 71 | 72 | self.sendbutton = Button( buttonframe, text="Send Command", 73 | command=self.rcvrCmdDialog ) 74 | self.sendbutton.pack( side=tkinter.LEFT ) 75 | 76 | Button( buttonframe, text="Shut Down", command=self.done, 77 | fg="red4" ).pack( side=tkinter.RIGHT ) 78 | 79 | # 80 | # text area for general messages 81 | # 82 | textframe = Frame( self ) 83 | textframe.pack( side=tkinter.BOTTOM, fill=tkinter.BOTH ) 84 | self.textarea = Text( textframe ) 85 | self.textarea.pack( side=tkinter.LEFT, fill=tkinter.BOTH ) 86 | scroll = Scrollbar( textframe ) 87 | scroll.config( command=self.textarea.yview ) 88 | scroll.pack( side=tkinter.RIGHT, fill=tkinter.BOTH ) 89 | self.textarea.config( yscrollcommand=scroll.set, height=15, width=80, 90 | wrap=tkinter.CHAR ) 91 | self.textarea.column = 0 92 | 93 | def incoming( self, fd, unknown ): 94 | # Read byte-by-byte until we hit a newline 95 | byteline = b"" # empty byte string 96 | while 1: 97 | try: 98 | c = self.from_client.read( 1 ) 99 | if (not c): 100 | break 101 | 102 | byteline += c 103 | if (c == b"\n"): 104 | break 105 | except IOError: 106 | break 107 | 108 | # Now convert the line of text bytes into 'normal' Python string 109 | # representation to make further parsing simpler 110 | line = byteline.decode() 111 | 112 | # 113 | # Read stuff from BistaticHub, with special handling for certain 114 | # lines; the rest just gets written to our logging area 115 | # 116 | if (len( line ) == 0): 117 | return 118 | # 119 | # Look for the leading strings we handle specially 120 | # 121 | specials = [ 122 | ("receiver:", self.handleRcvr), 123 | ("recording:", self.handleRecStatus), 124 | ("debuglevel:", self.handleDebugLevel), 125 | ("ncpthresh:", self.handleNCPThresh), 126 | ("status:", self.handleStatus), 127 | ("syncinfo:", self.handleSyncInfo) 128 | ] 129 | 130 | for string, handler in specials: 131 | match = re.search( string, line ) 132 | if (match): 133 | start = match.start() 134 | if (start != 0): 135 | self.log( line[:start] ) # log any extraneous stuff preceding the special 136 | handler( line[start:] ) 137 | 138 | # Return after we handle a match 139 | return 140 | 141 | # If the line wasn't handled above, just log it as an informational message 142 | self.log( line ) 143 | 144 | def handleRcvr( self, line ): 145 | # 146 | # Deal with receiver info line: 147 | # receiver: [] 148 | # 149 | match = re.search( 'receiver: *([0-9]+) +([^ ]+) +([0-9]+) (.*)', line ) 150 | if (match == None): 151 | self.log( "Bad 'receiver' line: " + line ) 152 | return 153 | 154 | rnum = match.group(1) 155 | name = match.group(2) 156 | enabled = match.group(3) 157 | extra = match.group(4) 158 | 159 | # 160 | # If we already have this receiver in our list, update its state, 161 | # otherwise create it 162 | # 163 | try: 164 | self.rcvrs[name].updateEnableState( enabled ) 165 | except KeyError: 166 | self.rcvrs[name] = Receiver( name, rnum, enabled, 167 | self.sendToClient, self ) 168 | self.pack() 169 | # 170 | # If we got extra information, put it into the receiver status 171 | # in red. (We also blank the sync info for the receiver) 172 | # 173 | self.rcvrs[name].updateStatus( extra, "red2" ) 174 | self.rcvrs[name].updateSyncInfo( "" ) 175 | 176 | def handleStatus( self, line ): 177 | # 178 | # Deal with status line: 179 | # status: 180 | # 181 | fields = line.split() 182 | rname = fields[1] 183 | status = ' '.join(fields[2:]) 184 | 185 | try: 186 | self.rcvrs[rname].updateStatus( status ) 187 | except KeyError: 188 | self.log( "Attempt to update status for unknown receiver " + 189 | rname + "\n" ) 190 | 191 | def handleSyncInfo( self, line ): 192 | # 193 | # Deal with syncinfo line: 194 | # syncinfo: p ... v ... 195 | # 196 | fields = line.split() 197 | rname = fields[1] 198 | p = fields[3:11] 199 | v = fields[12:20] 200 | line = "P " + " ".join(p) + " V " + " ".join(v) 201 | self.rcvrs[rname].updateSyncInfo( line ) 202 | 203 | def handleRecStatus( self, line ): 204 | self.recording = eval( line.split()[1] ) 205 | 206 | if (self.recording): 207 | statusString = "ON" 208 | color = "green4" 209 | else: 210 | statusString = "OFF" 211 | color = "red2" 212 | self.recbutton.config( text="Hub Recording is: " + statusString, 213 | fg=color ) 214 | 215 | def debugDialog( self ): 216 | newlevel = DebugLevelDialog( self, self.debuglevel ).result 217 | if (newlevel != None): 218 | self.sendToClient( "debuglevel " + repr(newlevel) ) 219 | 220 | def ncpDialog( self ): 221 | newthresh = NCPThreshDialog( self, self.ncpthresh ).result 222 | if (newthresh != None): 223 | self.sendToClient( "ncpthresh " + newthresh ) 224 | 225 | def rcvrCmdDialog( self ): 226 | try: 227 | cmd, recipient = RcvrCmdDialog( self, self.rcvrs ).result 228 | except TypeError: 229 | return 230 | 231 | if (recipient == "All"): 232 | rnum = -1 233 | else: 234 | rnum = self.rcvrs[recipient].rcvrNum 235 | 236 | self.sendToClient( "rcvrcommand " + cmd + ' ' + repr(rnum) ) 237 | 238 | def handleDebugLevel( self, line ): 239 | self.debuglevel = eval( line.split()[1] ) 240 | self.debugbutton.config( text="Debug Level: " + repr(self.debuglevel) ) 241 | 242 | def handleNCPThresh( self, line ): 243 | self.ncpthresh = eval( line.split()[1] ) 244 | self.ncpbutton.config( text="NCP Threshold: " + repr(self.ncpthresh) ) 245 | 246 | def log( self, text ): 247 | # 248 | # force line breaking if necessary 249 | # 250 | width = self.textarea.cget( "width" ) 251 | 252 | nleft = width - self.textarea.column 253 | while (len( text ) > nleft): 254 | partial = text[:nleft] 255 | self.textarea.insert( tkinter.END, partial + "\n" ) 256 | text = text[nleft-1:] 257 | self.textarea.column = 0 258 | nleft = width 259 | 260 | self.textarea.insert( tkinter.END, text ) 261 | if (text[-1] == '\n'): 262 | self.textarea.column = 0 263 | else: 264 | lastline = '\n'.split(text)[-1] 265 | self.textarea.column = self.textarea.column + len( lastline ) 266 | # 267 | # Just eval the line.column index as a float, then convert it 268 | # to an int to get our line count 269 | # 270 | nlines = int( eval( self.textarea.index( tkinter.END ) ) ) 271 | # 272 | # Keep our size down to 200 lines or fewer 273 | # 274 | nkill = nlines - 200 275 | if (nkill > 0): 276 | self.textarea.delete( "0.0", repr(nkill) + ".0" ) 277 | # 278 | # Scroll so that we keep the new stuff in the window 279 | # 280 | totallines = int( eval( self.textarea.index( tkinter.END ) ) ) 281 | winheight = self.textarea.cget( "height" ) 282 | top = 1.0 - (float( winheight - 4 ) / totallines) 283 | if top < 0: 284 | top = 0 285 | self.textarea.yview( "moveto", top ) 286 | 287 | def dumplog( self ): 288 | fname = "BistaticHub.log" 289 | try: 290 | f = open( fname, "w" ) 291 | f.write( self.textarea.get( 1.0, tkinter.END ) ) 292 | f.close() 293 | sys.stderr.write("Log information dumped to " + fname + "\n" ) 294 | except: 295 | sys.stderr.write( "Failure writing log file " + fname + "\n" ) 296 | 297 | 298 | def startclient( self ): 299 | pipe_a = os.pipe() 300 | pipe_b = os.pipe() 301 | 302 | if (os.fork()): 303 | os.close( pipe_a[0] ) 304 | os.close( pipe_b[1] ) 305 | self.to_client = os.fdopen( pipe_a[1], 'wb', 0 ) 306 | self.from_client = os.fdopen( pipe_b[0], 'rb', 0 ) 307 | # 308 | # set up our input file for non-blocking reads 309 | # 310 | fcntl.fcntl( self.from_client.fileno(), fcntl.F_SETFL, os.O_NDELAY ) 311 | else: 312 | os.close( pipe_a[1] ) 313 | os.close( pipe_b[0] ) 314 | os.dup2( pipe_a[0], 0 ) 315 | os.dup2( pipe_b[1], 1 ) 316 | os.dup2( 1, 2 ) 317 | 318 | prog = "BistaticHub" 319 | args = (prog,) + tuple( sys.argv[1:] ) 320 | os.execv( prog, args ) 321 | # 322 | # if execv returned, it's a problem... 323 | # 324 | sys.exit( 1 ) 325 | 326 | # Send the given string command to our client as 8-bit characters 327 | def sendToClient( self, cmd ): 328 | cmdbytes = (cmd + "\n").encode("utf-8") 329 | self.to_client.write( cmdbytes ) 330 | 331 | def toggleRecording( self ): 332 | if self.recording: 333 | self.sendToClient( "writeoff" ) 334 | else: 335 | self.sendToClient( "writeon" ) 336 | 337 | def haltChild( self ): 338 | signal.signal( signal.SIGCHLD, signal.SIG_DFL ) 339 | self.sendToClient( "exit" ) 340 | 341 | def done( self ): 342 | self.haltChild() 343 | sys.exit( 0 ) 344 | 345 | def sigExit( self, signum, stack ): 346 | sys.stderr.write( "Exiting on signal " + repr(signum) ) 347 | self.log( "Exiting on signal " + repr(signum) + "\n" ) 348 | self.dumplog() 349 | self.haltChild() 350 | sys.exit( 1 ) 351 | 352 | def childDied( self, signum, stack ): 353 | sys.stderr.write( "Child program died, so I'm quitting!\n" ) 354 | # 355 | # Try to grab any dying message we may have been left... 356 | # 357 | self.incoming( self.from_client.fileno(), 0 ) 358 | self.log( "(BistaticHub.py exiting on SIGCHLD)\n" ) 359 | self.dumplog() 360 | sys.exit( 1 ) 361 | 362 | 363 | class DebugLevelDialog( Dialog ): 364 | def __init__( self, master, currentlevel ): 365 | self.newlevel = IntVar() 366 | self.newlevel.set( currentlevel ) 367 | Dialog.__init__( self, master ) 368 | 369 | def body( self, master ): 370 | for i in range(4): 371 | Radiobutton( master, text=repr(i), variable=self.newlevel, 372 | value=i ).grid( row=0, column=i ) 373 | 374 | def apply( self ): 375 | self.result = self.newlevel.get() 376 | 377 | 378 | class NCPThreshDialog( Dialog ): 379 | def __init__( self, master, currentthresh ): 380 | self.currentval = currentthresh 381 | Dialog.__init__( self, master ) 382 | 383 | def body( self, master ): 384 | Label( master, text="NCP threshold:" ).grid( row=0, column=0 ) 385 | self.entry = Entry( master ) 386 | self.entry.insert( 0, self.currentval ) 387 | self.entry.grid( row=0, column=1 ) 388 | self.entry.config( width=5 ) 389 | 390 | def apply( self ): 391 | self.result = self.entry.get() 392 | 393 | 394 | class RcvrCmdDialog( Dialog ): 395 | def __init__( self, master, rcvrs ): 396 | self.rcvrs = rcvrs 397 | self.towhom = StringVar() 398 | self.towhom.set( "All" ) 399 | Dialog.__init__( self, master ) 400 | 401 | def body( self, master ): 402 | Label( master, text="Send:" ).grid( row=0, column=0 ) 403 | self.entry = Entry( master ) 404 | self.entry.grid( row=0, column=1 ) 405 | self.entry.config( width=5 ) 406 | Label( master, text="to" ).grid( row=0, column=2 ) 407 | self.mb = Menubutton( master, text=self.towhom.get(), borderwidth=2, 408 | relief=tkinter.RAISED ) 409 | self.mb.grid( row=0, column=3 ) 410 | menu = Menu( self.mb ) 411 | menu.add_radiobutton( label="All", variable=self.towhom, value="All", 412 | indicatoron=0, command=self.updateMenuButton ) 413 | 414 | for r in list(self.rcvrs.keys()): 415 | menu.add_radiobutton( label=r, variable=self.towhom, 416 | value=r, indicatoron=0, 417 | command=self.updateMenuButton ) 418 | self.mb['menu'] = menu 419 | 420 | def updateMenuButton( self ): 421 | self.mb.config( text=self.towhom.get() ) 422 | 423 | def apply( self ): 424 | self.result = ( self.entry.get(), self.towhom.get() ) 425 | 426 | 427 | class Receiver( Frame ): 428 | def __init__( self, name, rnum, enabled, sender, master=None ): 429 | Frame.__init__( self, master, relief=tkinter.SUNKEN, borderwidth=2 ) 430 | self.name = name 431 | self.pack( side=tkinter.TOP, fill=tkinter.X ) 432 | self.rcvrNum = rnum 433 | self.createWidgets() 434 | self.sendToClient = sender 435 | self.updateEnableState( enabled ) 436 | 437 | def updateEnableState( self, enabled ): 438 | self.enabled = enabled 439 | if self.enabled: 440 | self.label.config( fg="black" ) 441 | else: 442 | self.label.config( fg="gray60" ) 443 | self.status.config( text="" ) 444 | self.sync.config( text="" ) 445 | 446 | def updateStatus( self, status, color="black" ): 447 | self.status.config( text=status, fg=color ) 448 | 449 | def updateSyncInfo( self, info ): 450 | self.sync.config( text=info ) 451 | 452 | def createWidgets( self ): 453 | self.label = Label( self, text=self.name, width=20, fg="red", 454 | anchor=tkinter.E ) 455 | self.label.pack( side=tkinter.LEFT ) 456 | Button( self, command=self.toggleEnable ).pack( side=tkinter.LEFT ) 457 | self.status = Label( self, text="", anchor=tkinter.W ) 458 | self.status.pack( side=tkinter.TOP, fill=tkinter.X ) 459 | self.sync = Label( self, text="", anchor=tkinter.W ) 460 | self.sync.pack( side=tkinter.BOTTOM, fill=tkinter.X ) 461 | 462 | def toggleEnable( self ): 463 | if (self.enabled): 464 | cmd = "disable " + repr(self.rcvrNum) 465 | else: 466 | cmd = "enable " + repr(self.rcvrNum) 467 | 468 | self.sendToClient( cmd ) 469 | 470 | 471 | 472 | if __name__ == '__main__': 473 | BistaticHub().mainloop() 474 | --------------------------------------------------------------------------------