Bringing WiFi to the Cidco Mailstation
1/*
2 * WiFiStation
3 * Copyright (c) 2021 joshua stein <jcs@jcs.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "wifistation.h"
19
20struct eeprom_data *settings;
21
22bool serial_alive = true;
23bool mailstation_alive = false;
24
25WiFiUDP syslogUDPClient;
26Syslog syslog(syslogUDPClient, SYSLOG_PROTO_BSD);
27
28#define BOOKMARK_0 "klud.ge"
29
30void
31setup(void)
32{
33 static_assert(sizeof(struct eeprom_data) < EEPROM_SIZE,
34 "EEPROM_SIZE is not large enough to hold struct eeprom_data");
35
36 EEPROM.begin(EEPROM_SIZE);
37 settings = (struct eeprom_data *)EEPROM.getDataPtr();
38 if (memcmp(settings->magic, EEPROM_MAGIC_BYTES,
39 sizeof(settings->magic)) == 0) {
40 /* do migrations if needed based on current revision */
41 switch (settings->revision) {
42 case 1:
43 settings->http_server = 0;
44 /* FALLTHROUGH */
45 case 2:
46 memset(settings->bookmarks, 0,
47 BOOKMARK_SIZE * NUM_BOOKMARKS);
48 strcpy(settings->bookmarks[0], BOOKMARK_0);
49 /* FALLTHROUGH */
50 case 3:
51 settings->echo = 1;
52 settings->quiet = 0;
53 settings->verbal = 1;
54 }
55
56 if (settings->revision != EEPROM_REVISION) {
57 settings->revision = EEPROM_REVISION;
58 EEPROM.commit();
59 }
60 } else {
61 /* start over */
62 memset(settings, 0, sizeof(struct eeprom_data));
63 memcpy(settings->magic, EEPROM_MAGIC_BYTES,
64 sizeof(settings->magic));
65 settings->revision = EEPROM_REVISION;
66
67 settings->baud = 9600;
68
69 settings->telnet = 1;
70 strlcpy(settings->telnet_tterm, "ansi",
71 sizeof(settings->telnet_tterm));
72 /* msTERM defaults */
73 settings->telnet_tts_w = 64;
74 settings->telnet_tts_h = 15;
75
76 settings->http_server = 0;
77
78 settings->echo = 1;
79 settings->quiet = 0;
80 settings->verbal = 1;
81
82 memset(settings->bookmarks, 0,
83 BOOKMARK_SIZE * NUM_BOOKMARKS);
84 strcpy(settings->bookmarks[0], BOOKMARK_0);
85
86 EEPROM.commit();
87 }
88
89 syslog_setup();
90
91 Serial.begin(settings->baud);
92 delay(1000);
93
94 led_setup();
95 ms_setup();
96 led_reset();
97
98 WiFi.persistent(false);
99 WiFi.mode(WIFI_STA);
100
101 /* don't require wifi_pass in case it's an open network */
102 if (settings->wifi_ssid[0] == 0)
103 WiFi.disconnect();
104 else
105 WiFi.begin(settings->wifi_ssid, settings->wifi_pass);
106
107 http_setup();
108}
109
110void
111syslog_setup(void)
112{
113 if (settings->syslog_server[0])
114 syslog.server(settings->syslog_server, 514);
115 else
116 syslog.server(NULL, 514);
117}
118
119void
120led_setup(void)
121{
122 /* setup LEDs */
123 pinMode(pRedLED, OUTPUT);
124 pinMode(pBlueLED, OUTPUT);
125 led_reset();
126}
127
128void
129error_flash(void)
130{
131 digitalWrite(pRedLED, LOW);
132 digitalWrite(pBlueLED, HIGH);
133 delay(100);
134 digitalWrite(pRedLED, HIGH);
135 digitalWrite(pBlueLED, LOW);
136 delay(100);
137 digitalWrite(pBlueLED, HIGH);
138}
139
140void
141led_reset(void)
142{
143 digitalWrite(pRedLED, HIGH);
144 digitalWrite(pBlueLED, HIGH);
145}
146
147size_t
148outputf(const char *format, ...)
149{
150 va_list arg;
151 char temp[64];
152 char* buf;
153
154 va_start(arg, format);
155 size_t len = vsnprintf(temp, sizeof(temp), format, arg);
156 va_end(arg);
157
158 if (len > sizeof(temp) - 1) {
159 /* too big for stack buffer, malloc something bigger */
160 buf = (char *)malloc(len + 1);
161 if (!buf)
162 return 0;
163
164 va_start(arg, format);
165 vsnprintf(buf, len + 1, format, arg);
166 va_end(arg);
167 } else
168 buf = temp;
169
170 output(buf);
171
172 if (buf != temp)
173 free(buf);
174
175 return len;
176}
177
178int
179output(char c)
180{
181 if (serial_alive) {
182 Serial.write(c);
183 if (c == '\n')
184 Serial.flush();
185 }
186 if (mailstation_alive)
187 ms_write(c);
188
189 return 0;
190}
191
192int
193output(const char *str)
194{
195 size_t len = strlen(str);
196
197#ifdef OUTPUT_TRACE
198 syslog.logf(LOG_DEBUG, "output: \"%s\"", str);
199#endif
200
201 for (size_t i = 0; i < len; i++)
202 output(str[i]);
203
204 return 0;
205}
206
207int
208output(String str)
209{
210 size_t len = str.length();
211 char *buf = (char *)malloc(len + 1);
212 int ret;
213
214 if (buf == NULL)
215 return -1;
216
217 str.toCharArray(buf, len);
218 ret = output(buf);
219 free(buf);
220
221 return ret;
222}