Guest User

Untitled

a guest
Oct 17th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.12 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <termios.h>
  7. #include <argp.h>
  8.  
  9. /*
  10. Simple program to read configuration of U-Blox GPS serial port.
  11. */
  12.  
  13.  
  14. ///// begin ARGP stuff
  15.  
  16. const char *argp_program_version = "gpscfg 0.1";
  17. const char *argp_program_bug_address = "<tom@dilatush.com>";
  18. static char doc[] = "gpscfg - configure U-Blox GPS on Raspberry Pi 3 port serial0";
  19.  
  20. /* A description of the arguments we accept. */
  21. static char args_doc[] = "";
  22.  
  23. /* The options we understand. */
  24. static struct argp_option options[] = {
  25. { "baud", 'b', 0, 0, "Check baud rate of GPS" },
  26. { "read", 'r', 0, 0, "Read port configuration" },
  27. { "echo", 'e', 0, 0, "Echo GPS output to console" },
  28. { "quiet", 'q', 0, 0, "Quiet mode (fewer messages)" },
  29. { "toggle", 't', 0, 0, "Toggle baud rate between 9,600 and 115,200" },
  30. { "high", 'h', 0, 0, "Try synchronizing at 115,200 baud first" },
  31. { 0 }
  32. };
  33.  
  34. /* Used by main to communicate with parse_opt. */
  35. struct arguments {
  36. int baudCheck;
  37. int readPortCfg;
  38. int toggle;
  39. int echo;
  40. int quiet;
  41. int high;
  42. };
  43.  
  44. /* Parse a single option. */
  45. static error_t parse_opt (int key, char *arg, struct argp_state *state) {
  46. /* Get the input argument from argp_parse, which we
  47. know is a pointer to our arguments structure. */
  48. struct arguments *arguments = state->input;
  49.  
  50. switch (key) {
  51.  
  52. case 'r': arguments->readPortCfg = 1; break;
  53. case 'b': arguments->baudCheck = 1; break;
  54. case 'q': arguments->quiet = 1; break;
  55. case 't': arguments->toggle = 1; break;
  56. case 'e': arguments->echo = 1; break;
  57. case 'h': arguments->high = 1; break;
  58.  
  59. case ARGP_KEY_END:
  60. if( arguments->baudCheck + arguments->readPortCfg + arguments->echo
  61. + arguments->toggle == 0 )
  62. argp_usage(state);
  63. break;
  64.  
  65. default:
  66. return ARGP_ERR_UNKNOWN;
  67. }
  68. return 0;
  69. }
  70.  
  71. /* Our argp parser. */
  72. static struct argp argp = { options, parse_opt, args_doc, doc };
  73.  
  74. ///// end ARGP stuff
  75.  
  76.  
  77. typedef struct ubxMsg {
  78. int size;
  79. unsigned char* msg;
  80. int noMsg;
  81. int valid;
  82. int class;
  83. int id;
  84. int bodySize;
  85. unsigned char* body;
  86. } UBXMsg;
  87.  
  88. unsigned char portQueryBody[] = {
  89. 0xB5, 0x62, /* message header */ \
  90. 0x06, 0x00, /* message class and ID */ \
  91. 0x01, 0x00, /* message body length */ \
  92. 0x01, /* UART ID */ \
  93. 0x00, 0x00 /* checksum */ \
  94. };
  95. unsigned char save[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1D, 0xAB};
  96.  
  97. UBXMsg createUbxMsg( unsigned char class, unsigned char id, unsigned char* body, int bodySize ) {
  98. UBXMsg result;
  99. result.msg = calloc( bodySize + 8, 1 );
  100. result.msg[0] = 0xB5;
  101. result.msg[1] = 0x62;
  102. result.msg[2] = class;
  103. result.msg[3] = id;
  104. result.msg[4] = bodySize & 0xFF;
  105. result.msg[5] = bodySize >> 8;
  106. memcpy( result.msg + 6, body, bodySize );
  107.  
  108. // calculate Fletcher checksum for this message...
  109. unsigned char ck_a = 0;
  110. unsigned char ck_b = 0;
  111. int i;
  112. for( i = 2; i < bodySize + 6; i++ ) {
  113. ck_a += result.msg[i];
  114. ck_b += ck_a;
  115. }
  116. result.msg[bodySize + 6] = ck_a;
  117. result.msg[bodySize + 7] = ck_b;
  118.  
  119. result.size = bodySize + 8;
  120. result.bodySize = bodySize;
  121. result.id = id;
  122. result.class = class;
  123. result.valid = 1;
  124. result.noMsg = 0;
  125. result.body = body;
  126. return result;
  127. }
  128.  
  129. UBXMsg getPortQueryMsg() {
  130. unsigned char body[] = { 0x01 };
  131. return createUbxMsg( 0x06, 0x00, body, 1 );
  132. }
  133.  
  134.  
  135.  
  136. // returns character if available, otherwise -1
  137. int readUART( int fd ) {
  138.  
  139. // Read a character from the port, if there is one
  140. unsigned char rx_buffer[1];
  141. int rx_length = read( fd, (void*)rx_buffer, 1 ); //Filestream, buffer to store in, number of bytes to read (max)
  142. if (rx_length < 0)
  143. {
  144. if( rx_length < -1 ) {
  145. printf( "Read error, %d\n", rx_length );
  146. return -2;
  147. }
  148. return -1;
  149. }
  150. else if (rx_length == 0)
  151. {
  152. //No data waiting
  153. return -1;
  154. }
  155. else
  156. {
  157. //Bytes received
  158. return rx_buffer[0];
  159. }
  160. }
  161.  
  162.  
  163. // echoes characters received from GPS onto console; never exits
  164. void echo( int fd ) {
  165. while( 1 ) {
  166. usleep( 50 );
  167. int c = readUART( fd );
  168. if( c >= 0 ) printf( "%c", c );
  169. }
  170. }
  171.  
  172.  
  173. // waits up to five seconds for the given string to be read
  174. // returns 0 for failure, 1 for success
  175. int waitForString( int fd, char* str, int size ) {
  176. int attempts = 0;
  177. int gotIt = 0;
  178. int index = 0;
  179. while( (attempts < 100000) && (gotIt == 0) ) {
  180. usleep( 50 );
  181. int x = readUART( fd );
  182. if( x >= 0 ) {
  183. //printf("%c", x);
  184. if( x == str[index] ) {
  185. index++;
  186. if( index == size ) {
  187. gotIt = 1;
  188. }
  189. }
  190. else {
  191. index = 0;
  192. }
  193. }
  194. attempts++;
  195. }
  196. return gotIt;
  197. }
  198.  
  199.  
  200. // Waits up to five seconds for a known message ("$GNGGA") to appear,
  201. // returning 1 if synchronized, 0 otherwise.
  202. // this is needed because upon opening the port the UART's receiver may
  203. // not be synchronized to the data stream, and will return garbage data.
  204. // Once synchronized, it should stay synchronized.
  205. int syncRx( int fd ) {
  206. return (waitForString( fd, "$GNGGA,", 7 ) == 0 ) ? 0 : 1;
  207. }
  208.  
  209.  
  210. void setTermOptions( int fd, int baud ) {
  211.  
  212. struct termios options;
  213. tcgetattr( fd, &options );
  214. options.c_cflag = baud | CS8 | CLOCAL | CREAD;
  215. options.c_iflag = IGNPAR;
  216. options.c_oflag = 0;
  217. options.c_lflag = 0;
  218. tcflush( fd, TCIFLUSH );
  219. tcsetattr( fd, TCSANOW, &options );
  220. }
  221.  
  222.  
  223. // returns file descriptor or -1 if failure...
  224. // hint is 1 to try 115,200 baud first
  225. int openUART( int quiet, int hint ) {
  226.  
  227. int fd = -1;
  228. fd = open("/dev/serial0", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
  229.  
  230. if (fd == -1) {
  231. printf( "Can't open serial0 - possibly it's in use by another application\n" );
  232. return fd;
  233. }
  234.  
  235. // we try twice...
  236. int try = (hint ? B115200 : B9600);
  237. int i;
  238. for( i = 0; i < 2; i++ ) {
  239. setTermOptions( fd, try );
  240. if( syncRx( fd ) ) {
  241. char* baud = ((try == B9600) ? "9,600" : "115,200" );
  242. if( !quiet ) printf( "Synchronized at %s baud...\n", baud );
  243. return fd;
  244. }
  245. try = ((try == B9600) ? B115200 : B9600);
  246. }
  247.  
  248. // we failed, so close the port...
  249. close( fd );
  250. return -1;
  251. }
  252.  
  253. // Waits up to five seconds for a UBX message to be received.
  254. // Entire message is received, validated, and decoded.
  255. // If no message is received, the noMsg flag will be set.
  256. // If a valid message is received, the valid flag will be set.
  257. UBXMsg rcvUbxMsg( fd ) {
  258. struct ubxMsg result;
  259. result.noMsg = 1;
  260. result.valid = 0;
  261.  
  262. int attempts = 0;
  263. int gotIt = 0;
  264. int index = 0;
  265.  
  266. unsigned char header[6];
  267.  
  268. // first we read the six byte header starting with 0xB5 0x62...
  269. while( (attempts < 100000) && (gotIt == 0) ) {
  270. usleep( 50 );
  271. int x = readUART( fd );
  272. if( x >= 0 ) {
  273. header[index] = x;
  274. switch( index ) {
  275. case 0: if( x == 0xB5 ) index++; break;
  276. case 1: if( x == 0x62 ) index++; else index = 0; break;
  277. default: index++; if( index >= 6 ) gotIt = 1; break;
  278. }
  279. }
  280. attempts++;
  281. }
  282. if( !gotIt )
  283. return result; // noMsg flag is set by default...
  284.  
  285. // decode the header...
  286. result.bodySize = header[4] | (header[5] << 8);
  287. result.class = header[2];
  288. result.id = header[3];
  289.  
  290. // then we read the body, however long it is, plus the two byte checksum...
  291. gotIt = 0;
  292. index = 0;
  293. result.body = calloc( result.bodySize + 2, 1 );
  294.  
  295. while( (attempts < 100000) && (gotIt == 0) ) {
  296. usleep( 50 );
  297. int x = readUART( fd );
  298. if( x >= 0 ) {
  299. result.body[index++] = x;
  300. if( index >= result.bodySize + 2 )
  301. gotIt = 1;
  302. }
  303. attempts++;
  304. }
  305. if( !gotIt )
  306. return result; // noMsg flag is set by default...
  307.  
  308. // we got the message, but we're not sure it's valid yet...
  309. result.noMsg = 0;
  310.  
  311. // construct the raw message buffer...
  312. result.msg = calloc( result.bodySize + 8, 1 );
  313. memcpy( result.msg, header, 6 );
  314. memcpy( result.msg + 6, result.body, result.bodySize + 2 );
  315.  
  316. // now we check to see if the message is valid (checksum matches)...
  317. // calculate Fletcher checksum for this message...
  318. unsigned char ck_a = 0;
  319. unsigned char ck_b = 0;
  320. int i;
  321. for( i = 2; i < result.bodySize + 6; i++ ) {
  322. ck_a += result.msg[i];
  323. ck_b += ck_a;
  324. }
  325. if( (result.msg[result.bodySize + 6] == ck_a) && (result.msg[result.bodySize + 7] == ck_b) ) {
  326. result.valid = 1;
  327. }
  328. return result;
  329. }
  330.  
  331. // return 0 if error, 1 if succeeded
  332. int sendUbxMsg( int fd, UBXMsg msg ) {
  333.  
  334. // first we blast the message out...
  335. //printf("message size: %d\n", msg.size);
  336. int c = write( fd, msg.msg, msg.size );
  337.  
  338. free( msg.msg );
  339. return 1;
  340. }
  341.  
  342. // prints the body of the given UBX message in hex, or the raw message if the body is invalid
  343. void printUbxMsg( UBXMsg msg ) {
  344. int size = msg.body ? msg.bodySize : msg.size;
  345. unsigned char * buf = msg.body ? msg.body : msg.msg;
  346. printf( msg.body ? "body:" : "msg:" );
  347. int i;
  348. for( i = 0; i < size; i++ ) {
  349. printf( "%02x:", buf[i] );
  350. }
  351. printf( "\n" );
  352. }
  353.  
  354. // interprets the given port configuration message and prints the result
  355. void printUbxPortConfiguration( UBXMsg msg ) {
  356. if( msg.noMsg || !msg.valid ) {
  357. printf( "Missing or invalid port configuration message!\n" );
  358. return;
  359. }
  360.  
  361. // get the baud rate...
  362. int baud = msg.body[8] | (msg.body[9] << 8) | (msg.body[10] << 16) | (msg.body[11] << 24);
  363. printf( "%d baud\n", baud );
  364.  
  365. // get the mode...
  366. int mode = msg.body[4] | (msg.body[5] << 8) | (msg.body[6] << 16) | (msg.body[7] << 24);
  367. int bits = 0x03 & (mode >> 6);
  368. int parity = 0x07 & (mode >> 9);
  369. int stop = 0x03 & (mode >> 12);
  370. printf( "%d bits\n", bits + 5 );
  371. switch( parity ) {
  372. case 0: printf( "even parity\n" ); break;
  373. case 1: printf( "odd parity\n" ); break;
  374. case 4: case 5: printf( "no parity\n" ); break;
  375. default: printf( "invalid parity\n" ); break;
  376. }
  377. switch( stop ) {
  378. case 0: printf( "1 stop bit\n" ); break;
  379. case 1: printf( "1.5 stop bits\n" ); break;
  380. case 2: printf( "2 stop bits\n" ); break;
  381. case 3: printf( "0.5 stop bits\n" ); break;
  382. }
  383. }
  384.  
  385.  
  386. // toggles the UART's baud rate between 9,600 baud and 115,200 baud
  387. void toggle( int fd, int quiet ) {
  388.  
  389. // first we get the current GPS port configuration
  390. int result = sendUbxMsg( fd, getPortQueryMsg() );
  391. if( !result ) {
  392. printf( "Failed to send port query message!\n" );
  393. exit( 1 );
  394. }
  395. UBXMsg cc = rcvUbxMsg( fd );
  396. if( cc.noMsg || !cc.valid ) {
  397. printf( "Port query response missing or invalid!\n" );
  398. exit( 1 );
  399. }
  400.  
  401. // now we construct our new port configuration message...
  402. int curBaud = cc.body[8] | (cc.body[9] << 8) | (cc.body[10] << 16) | (cc.body[11] << 24);
  403. int newBaud = (curBaud == 9600) ? 115200: 9600;
  404. cc.body[8] = newBaud;
  405. cc.body[9] = newBaud >> 8;
  406. cc.body[10] = newBaud >> 16;
  407. cc.body[11] = newBaud >> 24;
  408. UBXMsg setCfg = createUbxMsg( 0x06, 0x00, cc.body, 20 );
  409.  
  410. // wait until we've had no rx data for at least three characters
  411. // we're hoping to hit a pause between the GPS sending bursts of characters
  412. int wt = (curBaud == 9600) ? 2813 : 234;
  413. int ct = 0;
  414. while( ct < wt ) {
  415. usleep( 10 );
  416. int c = readUART( fd );
  417. ct = (( c >= 0 ) ? 0 : ct + 10);
  418. }
  419.  
  420. // send the configuration message...
  421. result = sendUbxMsg( fd, setCfg );
  422. if( !result ) {
  423. printf( "Failed to send port configuration message!\n" );
  424. return;
  425. }
  426.  
  427. tcdrain( fd ); // wait for the preceding message to finish sending...
  428.  
  429. // we ignore the expected ACK, because we don't know what baud rate it's going
  430. // to come back in
  431. if( !quiet ) printf( "Port configuration changed to %d baud\n", newBaud );
  432. }
  433.  
  434.  
  435. int main( int argc, char *argv[] ) {
  436.  
  437. //// begin ARGP stuff
  438.  
  439. struct arguments arguments;
  440.  
  441. /* Default values. */
  442. arguments.baudCheck = 0;
  443. arguments.readPortCfg = 0;
  444. arguments.echo = 0;
  445. arguments.quiet = 0;
  446. arguments.toggle = 0;
  447. arguments.high = 0;
  448.  
  449. /* Parse our arguments; every option seen by parse_opt will
  450. be reflected in arguments. */
  451. argp_parse (&argp, argc, argv, 0, 0, &arguments);
  452.  
  453. //// end ARGP stuff
  454.  
  455. int fd = openUART( arguments.quiet, arguments.high );
  456. if( fd < 0 ) exit( 1 );
  457.  
  458. if( arguments.baudCheck ) {
  459. close( fd );
  460. exit( 0 );
  461. }
  462. else if( arguments.toggle ) {
  463. toggle( fd, arguments.quiet );
  464. }
  465. else if( arguments.readPortCfg ) {
  466. int result = sendUbxMsg( fd, getPortQueryMsg() );
  467. if( result ) {
  468. UBXMsg answer = rcvUbxMsg( fd );
  469. printUbxPortConfiguration( answer );
  470. }
  471. }
  472. else if( arguments.echo ) {
  473. echo( fd );
  474. }
  475. exit( 0 );
  476. }
Add Comment
Please, Sign In to add comment