├── .gitignore ├── LICENSE ├── README.md ├── adsb_encoder.cpp └── adsb_encoder.h /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 yangbinbin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # adsb_encoder 2 | ads-b encode 3 | -------------------------------------------------------------------------------- /adsb_encoder.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include "adsb_encoder.h" 5 | 6 | 7 | #define latz (15.0) 8 | #ifndef M_PI 9 | #define M_PI 3.14159265358979323846 // pi 10 | #endif 11 | 12 | #define MODES_GENERATOR_POLY 0xfff409U 13 | static unsigned int crc_table[256]; 14 | 15 | typedef struct cpr_pair 16 | { 17 | unsigned int YZ; 18 | unsigned int XZ; 19 | }cpr_pair_t; 20 | 21 | unsigned int modes_crc(unsigned char *buf, size_t len) 22 | { 23 | unsigned int rem = 0; 24 | size_t i; 25 | for (rem = 0, i = len; i > 0; --i) { 26 | rem = ((rem & 0x00ffff) << 8) ^ crc_table[*buf++ ^ ((rem & 0xff0000) >> 16)]; 27 | } 28 | 29 | return rem; 30 | } 31 | 32 | 33 | int CPR_NL(double lat) 34 | { 35 | #if 0 36 | if (lat < 0) 37 | lat = -lat; 38 | 39 | if (fabs(lat) >= 87.0) 40 | return 1; 41 | 42 | double U = 1 - cos(M_PI / (2 * latz)); 43 | double T = cos(M_PI / 180.0 * fabs(lat)); 44 | return static_cast(floor(2.0*M_PI* 1.0 / (acos(1 - U / (T*T))))); 45 | #endif 46 | 47 | if (lat < 0) lat = -lat; 48 | if (lat < 10.47047130) return 59; 49 | if (lat < 14.82817437) return 58; 50 | if (lat < 18.18626357) return 57; 51 | if (lat < 21.02939493) return 56; 52 | if (lat < 23.54504487) return 55; 53 | if (lat < 25.82924707) return 54; 54 | if (lat < 27.93898710) return 53; 55 | if (lat < 29.91135686) return 52; 56 | if (lat < 31.77209708) return 51; 57 | if (lat < 33.53993436) return 50; 58 | if (lat < 35.22899598) return 49; 59 | if (lat < 36.85025108) return 48; 60 | if (lat < 38.41241892) return 47; 61 | if (lat < 39.92256684) return 46; 62 | if (lat < 41.38651832) return 45; 63 | if (lat < 42.80914012) return 44; 64 | if (lat < 44.19454951) return 43; 65 | if (lat < 45.54626723) return 42; 66 | if (lat < 46.86733252) return 41; 67 | if (lat < 48.16039128) return 40; 68 | if (lat < 49.42776439) return 39; 69 | if (lat < 50.67150166) return 38; 70 | if (lat < 51.89342469) return 37; 71 | if (lat < 53.09516153) return 36; 72 | if (lat < 54.27817472) return 35; 73 | if (lat < 55.44378444) return 34; 74 | if (lat < 56.59318756) return 33; 75 | if (lat < 57.72747354) return 32; 76 | if (lat < 58.84763776) return 31; 77 | if (lat < 59.95459277) return 30; 78 | if (lat < 61.04917774) return 29; 79 | if (lat < 62.13216659) return 28; 80 | if (lat < 63.20427479) return 27; 81 | if (lat < 64.26616523) return 26; 82 | if (lat < 65.31845310) return 25; 83 | if (lat < 66.36171008) return 24; 84 | if (lat < 67.39646774) return 23; 85 | if (lat < 68.42322022) return 22; 86 | if (lat < 69.44242631) return 21; 87 | if (lat < 70.45451075) return 20; 88 | if (lat < 71.45986473) return 19; 89 | if (lat < 72.45884545) return 18; 90 | if (lat < 73.45177442) return 17; 91 | if (lat < 74.43893416) return 16; 92 | if (lat < 75.42056257) return 15; 93 | if (lat < 76.39684391) return 14; 94 | if (lat < 77.36789461) return 13; 95 | if (lat < 78.33374083) return 12; 96 | if (lat < 79.29428225) return 11; 97 | if (lat < 80.24923213) return 10; 98 | if (lat < 81.19801349) return 9; 99 | if (lat < 82.13956981) return 8; 100 | if (lat < 83.07199445) return 7; 101 | if (lat < 83.99173563) return 6; 102 | if (lat < 84.89166191) return 5; 103 | if (lat < 85.75541621) return 4; 104 | if (lat < 86.53536998) return 3; 105 | if (lat < 87.00000000) return 2; 106 | else return 1; 107 | 108 | } 109 | 110 | int CPR_N(double lat, int odd) 111 | { 112 | int nl = CPR_NL(lat) - (odd ? 1 : 0); 113 | if (nl < 1) 114 | nl = 1; 115 | return nl; 116 | 117 | } 118 | double CPR_MOD(double x, double y) 119 | { 120 | return x - y*floor(x / y); 121 | } 122 | 123 | double CPR_DLAT(int odd, int surface) 124 | { 125 | double tmp = 0; 126 | 127 | if (surface == 1) 128 | tmp = 90.0; 129 | else 130 | tmp = 360.0; 131 | double nzcalc = (odd ? 59.0 : 60.0); 132 | if (nzcalc == 0) 133 | return tmp; 134 | else 135 | return tmp / nzcalc; 136 | } 137 | double CPR_DLON(double rlat, int odd, int surface) 138 | { 139 | double tmp = 0; 140 | 141 | if (surface == 1) 142 | tmp = 90.0; 143 | else 144 | tmp = 360.0; 145 | double nzcalc = CPR_N(rlat, odd); 146 | if (nzcalc == 0) 147 | return tmp; 148 | else 149 | return tmp / nzcalc; 150 | } 151 | 152 | 153 | 154 | cpr_pair_t cpr_encode(double lat, double lon, int odd, int surface) 155 | { 156 | double NbPow = 0; 157 | if (surface) 158 | NbPow = pow(2.0, 19); 159 | else 160 | NbPow = pow(2.0, 17); 161 | double Dlat = CPR_DLAT(odd, 0); 162 | unsigned int YZ = static_cast(floor(NbPow*CPR_MOD(lat, Dlat) / Dlat + 0.5)); 163 | double Rlat = Dlat*(1.0*YZ / NbPow + floor(lat / Dlat)); 164 | double Dlon = CPR_DLON(Rlat, odd, 0); 165 | unsigned int XZ = static_cast(floor(NbPow*CPR_MOD(lon, Dlon) / Dlon + 0.5)); 166 | 167 | cpr_pair_t v; 168 | v.YZ = YZ & 0x1FFFF; 169 | v.XZ = XZ & 0x1FFFF; 170 | return v; 171 | } 172 | 173 | unsigned int encode_altitude(double ft) 174 | { 175 | unsigned int i = static_cast((ft + 1012.5) / 25); 176 | if (i < 0) 177 | i = 0; 178 | if (i > 0x7FF) 179 | i = 0x7FF; 180 | return ((i & 0x7F0) << 1) | 0x010 | (i & 0x00F); 181 | } 182 | 183 | unsigned char surface_movement(unsigned int knot) 184 | { 185 | if (knot > 175) 186 | return 124; 187 | else if (knot > 100) 188 | return static_cast((knot - 100) / 5.0 + 109); 189 | else if (knot > 70) 190 | return static_cast((knot - 70) / 2.0 + 94); 191 | else if (knot > 15) 192 | return static_cast((knot - 15) / 1.0 + 39); 193 | else if (knot > 2) 194 | return static_cast((knot - 2) / 0.5 + 13); 195 | else if (knot > 1) 196 | return static_cast((knot - 1) / 0.25 + 9); 197 | else if (knot > 0.125) 198 | return static_cast((knot - 0.125) / 0.2700833 + 3); 199 | else if (knot > 0) 200 | return 2; 201 | else if (knot == 0) 202 | return 1; 203 | else 204 | return 0; 205 | } 206 | 207 | unsigned char surface_heading(double heading) 208 | { 209 | double n = 360.0 / 128.0; 210 | return static_cast(heading / n); 211 | } 212 | 213 | 214 | frame_data_t _make_surface_position_frame( 215 | unsigned short metype, 216 | unsigned int addr, 217 | unsigned int elat, unsigned int elon, 218 | unsigned char knot, bool heading_valid, unsigned char heading, 219 | unsigned int oddflag, DF df) 220 | { 221 | frame_data_t framev; 222 | memset((void*)&framev, 0, sizeof(frame_data_t)); 223 | unsigned char* frame = framev.msg; 224 | 225 | unsigned char imf = 0; 226 | if (df == DF17) 227 | { 228 | frame[0] = (17 << 3) | (6); 229 | imf = 0; 230 | } 231 | else if (df == DF18) 232 | { 233 | frame[0] = (18 << 3) | (2); 234 | imf = 0; 235 | } 236 | else if (df == DF18ANON) 237 | { 238 | frame[0] = (18 << 3) | (5); 239 | imf = 0; 240 | } 241 | else 242 | { 243 | frame[0] = (18 << 3) | (2); 244 | imf = 1; 245 | } 246 | 247 | 248 | frame[1] = (addr >> 16) & 255; 249 | frame[2] = (addr >> 8) & 255; 250 | frame[3] = addr & 255; 251 | 252 | frame[4] = (metype << 3); 253 | 254 | frame[4] |= ((knot >> 4) & 0x07); 255 | frame[5] = knot << 4; 256 | 257 | 258 | if (heading_valid) 259 | { 260 | frame[5] |= 0x08; 261 | frame[5] |= (heading >> 4) & 0x07; 262 | frame[6] = (heading << 4)&0xF0; 263 | } 264 | 265 | if (imf) 266 | frame[6] |= 0x08; 267 | 268 | if (oddflag) 269 | frame[6] |= 4; 270 | 271 | frame[6] |= (elat >> 15) & 3; 272 | frame[7] = (elat >> 7) & 255; 273 | frame[8] = (elat & 127) << 1; 274 | frame[8] |= (elon >> 16) & 1; 275 | frame[9] = (elon >> 8) & 255; 276 | frame[10] = elon & 255; 277 | 278 | unsigned int crc = modes_crc(frame, 11); 279 | frame[11] = (crc >> 16) & 255; 280 | frame[12] = (crc >> 8) & 255; 281 | frame[13] = crc & 255; 282 | return framev; 283 | } 284 | 285 | 286 | 287 | 288 | frame_data_t _make_air_position_frame(unsigned short metype, unsigned int addr, 289 | unsigned int elat, unsigned int elon, unsigned int ealt, 290 | unsigned int oddflag, DF df) 291 | { 292 | frame_data_t framev; 293 | memset((void*)&framev, 0, sizeof(frame_data_t)); 294 | unsigned char* frame = framev.msg; 295 | 296 | unsigned char imf = 0; 297 | if (df == DF17) 298 | { 299 | frame[0] = (17 << 3) | (6); 300 | imf = 0; 301 | } 302 | else if (df == DF18) 303 | { 304 | frame[0] = (18 << 3) | (2); 305 | imf = 0; 306 | } 307 | else if (df == DF18ANON) 308 | { 309 | frame[0] = (18 << 3) | (5); 310 | imf = 0; 311 | } 312 | else 313 | { 314 | frame[0] = (18 << 3) | (2); 315 | imf = 1; 316 | } 317 | 318 | frame[1] = (addr >> 16) & 255; 319 | frame[2] = (addr >> 8) & 255; 320 | frame[3] = addr & 255; 321 | frame[4] = (metype << 3); 322 | frame[4] |= imf; 323 | frame[5] = (ealt >> 4) & 255; 324 | frame[6] = (ealt & 15) << 4; 325 | 326 | if (oddflag) 327 | frame[6] |= 4; 328 | 329 | frame[6] |= (elat >> 15) & 3; 330 | frame[7] = (elat >> 7) & 255; 331 | frame[8] = (elat & 127) << 1; 332 | frame[8] |= (elon >> 16) & 1; 333 | frame[9] = (elon >> 8) & 255; 334 | frame[10] = elon & 255; 335 | 336 | unsigned int crc = modes_crc(frame, 11); 337 | frame[11] = (crc >> 16) & 255; 338 | frame[12] = (crc >> 8) & 255; 339 | frame[13] = crc & 255; 340 | return framev; 341 | } 342 | 343 | 344 | frame_data_t make_air_position_frame(unsigned short metype, //[5,18] , [20,22] 345 | unsigned int addr, 346 | double lat, double lon, 347 | double alt, //ft 348 | unsigned int oddflag, DF df) 349 | { 350 | 351 | unsigned int ealt = encode_altitude(alt); 352 | cpr_pair_t cpr_value = cpr_encode(lat, lon, oddflag, AIR_POS); 353 | 354 | return _make_air_position_frame(metype, addr, cpr_value.YZ, cpr_value.XZ, ealt, oddflag, df); 355 | } 356 | 357 | 358 | frame_data_t make_surface_position_frame( 359 | unsigned short metype, //[5,8] 360 | unsigned int addr, 361 | double lat, double lon, 362 | unsigned int knot, bool heading_valid, double heading, 363 | unsigned int oddflag, DF df) 364 | { 365 | cpr_pair_t cpr_value = cpr_encode(lat, lon, oddflag, SURFACE_POS); 366 | 367 | unsigned char mv_knot = surface_movement(knot); 368 | unsigned char mv_heading = surface_heading(heading); 369 | 370 | return _make_surface_position_frame(metype, 371 | addr, cpr_value.YZ, cpr_value.XZ, 372 | mv_knot, heading_valid, mv_heading, 373 | oddflag, df); 374 | } 375 | 376 | 377 | unsigned short encode_vrate(double vr) 378 | { 379 | unsigned short signbit = 0; 380 | if (vr < 0) 381 | { 382 | signbit = 0x200; 383 | vr = 0 - vr; 384 | } 385 | unsigned short vr_s = static_cast(vr / 64.0 + 1.5); 386 | 387 | if (vr_s > 511) 388 | return 511 | signbit; 389 | else 390 | return vr_s | signbit; 391 | } 392 | 393 | 394 | 395 | unsigned short encode_velocity(double kts, bool supersonic) 396 | { 397 | unsigned short signbit = 0; 398 | if (kts < 0) 399 | { 400 | signbit = 0x400; 401 | kts = 0 - kts; 402 | } 403 | 404 | if (supersonic) 405 | kts /= 4.0; 406 | 407 | unsigned short kts_s = static_cast(kts + 1.5); 408 | 409 | if (kts_s > 1023) 410 | return 1023 | signbit; 411 | else 412 | return kts_s | signbit; 413 | } 414 | static char *ais_charset = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"; 415 | unsigned char ais_charset_idx(unsigned char c) 416 | { 417 | size_t len = strlen(ais_charset); 418 | for (size_t i = 0; i < len; i++) 419 | { 420 | if (ais_charset[i] == c) 421 | return static_cast(i & 0xFF); 422 | } 423 | 424 | return 0; 425 | } 426 | 427 | frame_data_t make_aircraft_identification_frame(unsigned int addr, 428 | unsigned char callsign[8], 429 | unsigned short category_set, 430 | unsigned short Category, 431 | DF df) 432 | { 433 | frame_data_t framev; 434 | memset((void*)&framev, 0, sizeof(frame_data_t)); 435 | unsigned char* frame = framev.msg; 436 | 437 | if (df == DF17) 438 | frame[0] = (17 << 3) | (6); 439 | else if (df == DF18) 440 | frame[0] = (18 << 3) | (2); 441 | else if (df == DF18ANON) 442 | frame[0] = (18 << 3) | (5); 443 | else 444 | frame[0] = (18 << 3) | (2); 445 | 446 | frame[1] = (addr >> 16) & 255; 447 | frame[2] = (addr >> 8) & 255; 448 | frame[3] = addr & 255; 449 | frame[4] = (category_set << 3); 450 | frame[4] |= (Category & 0x07); 451 | 452 | 453 | #define GET_CHAR(n) \ 454 | c = callsign[n]; \ 455 | if (c == 0) \ 456 | goto calc_crc; 457 | 458 | 459 | unsigned char c = 0; 460 | 461 | GET_CHAR(0); 462 | unsigned char c1 = ais_charset_idx(c); 463 | frame[5] = c1 << 2; 464 | 465 | GET_CHAR(1); 466 | unsigned char c2 = ais_charset_idx(c); 467 | frame[5] |= ((c2 >> 4) & 0x03); 468 | frame[6] = (c2 << 4); 469 | 470 | GET_CHAR(2); 471 | unsigned char c3 = ais_charset_idx(c); 472 | frame[6] |= ((c3 >> 2) & 0x0F); 473 | frame[7] = c3 << 6; 474 | 475 | GET_CHAR(3); 476 | unsigned char c4 = ais_charset_idx(c); 477 | frame[7] |= c4 & 0x3F; 478 | 479 | GET_CHAR(4); 480 | unsigned char c5 = ais_charset_idx(c); 481 | frame[8] = c5 << 2; 482 | 483 | GET_CHAR(5); 484 | unsigned char c6 = ais_charset_idx(c); 485 | frame[8] |= ((c6 >> 4) & 0x03); 486 | frame[9] = (c6 << 4); 487 | 488 | GET_CHAR(6); 489 | unsigned char c7 = ais_charset_idx(c); 490 | frame[9] |= ((c7 >> 2) & 0x0F); 491 | frame[10] = c7 << 6; 492 | 493 | GET_CHAR(7); 494 | unsigned char c8 = ais_charset_idx(c); 495 | frame[10] |= c8 & 0x3F; 496 | 497 | 498 | calc_crc: 499 | unsigned int crc = modes_crc(frame, 11); 500 | frame[11] = (crc >> 16) & 255; 501 | frame[12] = (crc >> 8) & 255; 502 | frame[13] = crc & 255; 503 | return framev; 504 | 505 | } 506 | 507 | 508 | frame_data_t make_velocity_frame(unsigned int addr, 509 | double nsvel, //南北方向速度(kts ,北正向) 510 | double ewvel, //东西方向速度(kts ,东正向) 511 | double vrate, //升速(ft/min,上升正向) 512 | DF df) 513 | { 514 | frame_data_t framev; 515 | memset((void*)&framev, 0, sizeof(frame_data_t)); 516 | unsigned char* frame = framev.msg; 517 | 518 | bool supersonic = (fabs(nsvel) > 1000) || (fabs(ewvel) > 1000); 519 | unsigned short e_ns = encode_velocity(nsvel, supersonic); 520 | unsigned short e_ew = encode_velocity(ewvel, supersonic); 521 | unsigned short e_vr = encode_vrate(vrate); 522 | 523 | unsigned char imf = 0; 524 | if (df == DF17) 525 | { 526 | frame[0] = (17 << 3) | (6); 527 | imf = 0; 528 | } 529 | else if (df == DF18) 530 | { 531 | frame[0] = (18 << 3) | (2); 532 | imf = 0; 533 | } 534 | else if (df == DF18ANON) 535 | { 536 | frame[0] = (18 << 3) | (5); 537 | imf = 0; 538 | } 539 | else 540 | { 541 | frame[0] = (18 << 3) | (2); 542 | imf = 1; 543 | } 544 | 545 | 546 | frame[1] = (addr >> 16) & 255; 547 | frame[2] = (addr >> 8) & 255; 548 | frame[3] = addr & 255; 549 | frame[4] = (19 << 3); 550 | 551 | if (supersonic) 552 | frame[4] |= 2; 553 | else 554 | frame[4] |= 1; 555 | 556 | frame[5] = (imf << 7); 557 | frame[5] |= (e_ew >> 8) & 7; 558 | frame[6] = (e_ew & 255); 559 | frame[7] = (e_ns >> 3) & 255; 560 | frame[8] = (e_ns & 7) << 5; 561 | frame[8] |= 16; 562 | frame[8] |= (e_vr >> 6) & 15; 563 | frame[9] = (e_vr & 63) << 2; 564 | frame[10] = 0; 565 | 566 | 567 | unsigned int crc = modes_crc(frame, 11); 568 | frame[11] = (crc >> 16) & 255; 569 | frame[12] = (crc >> 8) & 255; 570 | frame[13] = crc & 255; 571 | return framev; 572 | } 573 | 574 | 575 | int modescrc_module_init() 576 | { 577 | int i; 578 | 579 | for (i = 0; i < 256; ++i) { 580 | unsigned int c = i << 16; 581 | int j; 582 | for (j = 0; j < 8; ++j) { 583 | if (c & 0x800000) 584 | c = (c << 1) ^ MODES_GENERATOR_POLY; 585 | else 586 | c = (c << 1); 587 | } 588 | 589 | crc_table[i] = c & 0x00ffffff; 590 | } 591 | return 0; 592 | } 593 | 594 | 595 | 596 | void adsb_encoder_init() 597 | { 598 | modescrc_module_init(); 599 | } 600 | -------------------------------------------------------------------------------- /adsb_encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __ADSB_ENCODER_INCLUDE__ 2 | #define __ADSB_ENCODER_INCLUDE__ 3 | 4 | 5 | enum DF { DF17 , DF18 , DF18ANON , DF18TRACK}; 6 | 7 | 8 | typedef struct frame_data 9 | { 10 | unsigned char msg[14]; 11 | }frame_data_t; 12 | 13 | 14 | #define CPR_ODD 1 15 | #define CPR_EVEN 0 16 | 17 | #define Category_Set_D 1 18 | #define Category_Set_C 2 19 | #define Category_Set_B 3 20 | #define Category_Set_A 4 21 | 22 | #define AIR_POS 0 23 | #define SURFACE_POS 1 24 | 25 | 26 | /* 27 | adsb编码初始化 28 | */ 29 | void adsb_encoder_init(); 30 | 31 | 32 | /* 33 | 生成空中位置报文 34 | */ 35 | frame_data_t make_air_position_frame( 36 | unsigned short metype, //[9,18] , [20,22] 37 | unsigned int addr, 38 | double lat, 39 | double lon, 40 | double alt, //ft 41 | unsigned int oddflag, 42 | DF df); 43 | 44 | /* 45 | 生成地面位置报文 46 | */ 47 | frame_data_t make_surface_position_frame( 48 | unsigned short metype, //[5,8] 49 | unsigned int addr, 50 | double lat, double lon, 51 | unsigned int knot, //地面速度(knot) 52 | bool heading_valid, //heading是否有效 53 | double heading, //速度方向(0~360) 54 | unsigned int oddflag, DF df); 55 | 56 | 57 | /* 58 | 生成身份类别报文 59 | */ 60 | frame_data_t make_aircraft_identification_frame( 61 | unsigned int addr, 62 | unsigned char callsign[8], //航班号,不足8字节的位置补0x00 63 | unsigned short category_set, 64 | unsigned short Category, 65 | DF df); 66 | 67 | /* 68 | 生成速度(ground speed)报文 69 | */ 70 | frame_data_t make_velocity_frame( 71 | unsigned int addr, 72 | double nsvel, //南北方向速度(kts ,北正向) 73 | double ewvel, //东西方向速度(kts ,东正向) 74 | double vrate, //升速(ft/min,上升正向) 75 | DF df); 76 | 77 | 78 | #endif 79 | --------------------------------------------------------------------------------