summaryrefslogtreecommitdiff
path: root/monitor_proto.c
blob: daadf81894e495f07bbba11b4c94138a61f18136 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Prototype file for a gpsmon monitor object.
 *
 * This file is Copyright (c) 2010-2018 by the GPSD project
 * SPDX-License-Identifier: BSD-2-clause
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <assert.h>
#include <unistd.h>

#include "gpsd.h"
#include "bits.h"
#include "gpsmon.h"

/*
 * Replace PROTO everywhere with the name of the GPSD driver describing
 * the device you want to support.
 *
 * gpsmon basically sits in a loop reading packets, using the same layer
 * as gpsd to dispatch on packet type to select an active device driver.
 * Your monitor object will become the handler for incoming packets whenever
 * the driver your object points at is selected.
 *
 * A comment following the method descriptions explains some available
 * helper functions.
 */

extern const struct gps_type_t driver__proto_;

static bool PROTO_initialize(void)
{
    /*
     * This function is called when your monitor object is activated.
     *
     * When you enter it, two windows will be accessible to you; (1)
     * devicewin, just below the status and command line at top of
     * screen, and (2) packetwin, taking up the rest of the screen below
     * it; packetwin will be enabled for scrolling. Note, however,
     * that you cannot necessarily update packetwin safely, as it may be NULL
     * if the screen has no lines left over after allocating devicewin;
     * you'll need to check this in your code.
     *
     * Use this method to paint windowframes and legends on the
     * freshly initialized device window.  You can also use this
     * method to send probes to the device, e.g. to elicit a response
     * telling you firmware rev levels or whatever.
     */

    /* return false if the window allocation failed; gpsmon will abort */
    return true;
}

static void PROTO_update(void)
{
    /*
     * Called on each packet received.  The packet will be accessible in
     * session.lexer.outbuffer and the length in session.lexer.outbuflen.
     * If the device is NMEA, session.driver.nmea.fields[] will contain the
     * array of unconverted field strings, including the tag in slot zero
     * but not including the checksum or trailing \r\n.
     *
     * Use this function to update devicewin.  The packet will be echoed to
     * packetwin immediately after this function is called; you can use this
     * function to write a prefix on the line.
     *
     * Helpers available include (1) toff_update, for throwing the
     * TOFF data from the last time fix on the screen, and (2)
     * pps_update, for throwing the PPS data from the last 1PPS event on
     * the screen, and
     */
}

static int PROTO_command(char line[])
{
    /*
     * Interpret a command line.  Whatever characters the user types will
     * be echoed in the command buffer at the top right of the display. When
     * he/she presses enter the command line will be passed to this function
     * for interpretation.  Note: packet receipt is suspended while this
     * function is executing.
     *
     * This method is optional.  If you set the command method pointer to
     * NULL, gpsmon will behave sanely, accepting no device-specific commands.
     *
     * It is a useful convention to use uppercase letters for
     * driver-specific commands and leave lowercase ones for the
     * generic gpsmon ones.
     */
    assert(strlen(line));

    /*
     * Return COMMAND_UNKNOWN to tell gpsmon you can't interpret the line, and
     * it will be passed to the generic command interpreter to be handled there.
     * You can alse return COMMAND_MATCH to tell it you handled the command,
     * or COMMAND_TERMINATE to tell gpsmon you handled it and gpsmon should
     * terminate.
     */
    return COMMAND_UNKNOWN;
}

static void PROTO_wrap(void)
{
    /*
     * Deinitialize any windows you created in PROTO_initialize.
     * This will be called when gpsmon switches drivers due to seeing
     * a new packet type.
     */
}

/*
 * Use mmt = monitor method table as a suffix for naming these things
 * Yours will need to be added to the monitor_objects table in gpsmon.c,
 * then of course you need to link your module into gpsmon.
 */
const struct monitor_object_t PROTO_mmt = {
    .initialize = PROTO_initialize,
    .update = PROTO_update,
    .command = PROTO_command,
    .wrap = PROTO_wrap,
    .min_y = 23, .min_x = 80,	/* size of the device window */
    /*
     * The gpsd driver type for your device.  gpsmon will use the mode_switcher
     * method for 'n', the speed_switcher for 's', and the control_send method
     * for 'c'.  Additionally, the driver type name will be displayed before
     * the '>' command prompt in the top line of the display.
     */
    .driver = &PROTO_binary,
};

/*
 * Helpers:
 *
 * bool monitor_control_send(unsigned char *buf, size_t len)
 *    Ship a packet payload to the device.  Calls the driver send_control()
 *    method to add headers/trailers/checksum; also dumps the sent
 *    packet to the packet window, if the send_control() is playing
 *    nice by using session.msgbuf to assemble the message.
 *
 * void monitor_log(const char *fmt, ...)
 *    Write a message to the packet window.  Safe if the packet window
 *    is not on screen.
 *
 * void monitor_complain(const char *fmt, ...)
 *    Post an error message to the command window, wait till user presses a key.
 *    You get to make sure the message will fit.
 *
 * void monitor_fixframe(WINDOW *win)
 *    Fix the frame of win to the right of the current location by redrawing
 *    ACS_VLINE there.  Useful after doing wclrtoeol() and writing on the
 *    line.
 *
 * The libgpsd session object is accessible as the global variable 'session'.
 */