-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmodem.ts
160 lines (149 loc) · 5.5 KB
/
modem.ts
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
160
/**
* Modem functionality to send and received AT commands and responses.
*
* @author Matthias L. Jugel
*/
//% weight=2 color=#f2c10d icon="\uf0ec"
//% advanced=true
//% parts="modem
namespace modem {
// keep the serial port settings for logging
let TX = SerialPin.C17;
let RX = SerialPin.C16;
let BAUD = BaudRate.BaudRate9600;
// the AT prefix, this may need to have even more characters, like "\rAT"
let AT_PREFIX = "AT";
// enabling DEBUG allows to follow the AT flow on the USB serial port
// this switches the serial back and forth and introduces delays
let DEBUG = false;
/**
* Initialize the modem with the corresponding serial pins and baud rate.
* @param {SerialPin} tx the modem transmission pins, eg: SerialPin.C17
* @param {SerialPin} rx the modem reception pin, eg: SerialPin.C16
* @param {BaudRate} rate the new baud rate, eg: BaudRate.BaudRate9600
*/
//% weight=100
//% blockId=modem_init block="initialize Modem|TX %tx|RX %rx|at baud rate %rate"
//% blockExternalInputs=1
//% parts="modem"
export function init(tx: SerialPin, rx: SerialPin, rate: BaudRate): void {
// initialize serial port
TX = tx;
RX = rx;
BAUD = rate;
serial.redirect(TX, RX, BAUD);
serial.setReceiveBufferSize(100);
}
/**
* Send an AT command to the modem module. Just provide the actual
* command, not the AT prefix, like this AT("+CGMI?"). Ignores the
* AT command response completely
* @param command the command to be sent without AT prefix
*/
//% weight=80
//% blockId=modem_pushat block="send AT %command"
//% parts="modem"
export function pushAT(command: string): void {
if (DEBUG) log("+++", AT_PREFIX + command);
serial.writeString(AT_PREFIX + command + "\r\n");
}
/**
* Send an AT command and expect either OK or ERROR response.
* Returns all response lines.
* @param {string} command the command to send without AT prefix
* @returns {Array<string>} an array of lines received
*/
//% weight=80
//% blockId=modem_sendat block="send AT %command and receive"
//% parts="modem"
export function sendAT(command: string): Array<string> {
basic.pause(100);
if (DEBUG) log("+++", AT_PREFIX + command);
serial.writeString(AT_PREFIX + command + "\r\n");
return receiveResponse((line: string) => {
return line == "OK" || line == "ERROR";
});
}
/**
* Wait for a response from the modem and collect all lines until the
* condition returns true. Returns all received lines.
* @param {(line: string) => boolean} cond
* @returns {Array<string>} an array of lines received
*/
//% weight=10
//% blockId=modem_receiveresponse block="wait for response %cond"
//% parts="modem"
export function receiveResponse(cond: (line: string) => boolean): Array<string> {
let line = "";
let received: Array<string> = [];
do {
line = serial.read("\r\n");
if (line.length > 0) received.push(line);
} while (line.length == 0 || !cond(line));
if (DEBUG) logArray("---", received);
return received;
}
/**
* Send an AT command to the modem module and expect OK. Just provide the actual
* command, not the AT prefix, like this AT("+CGMI?"). This function
* only returns whether the command was executed successful or not.
* @param command the command to be sent without AT prefix
*/
//% weight=80
//% blockId=modem_expectok block="check AT %command|response OK?"
//% parts="modem"
export function expectOK(command: string): boolean {
let response = sendAT(command);
return response[response.length - 1] == "OK";
}
/**
* Set the AT prefix. If your modem has special requirements, like
* an empty line or just a \r before each AT, set it here.
* @param prefix the AT prefix, eg: AT
*/
//% weight=80
//% blockId=modem_setatprefix block="set AT prefix %prefix"
//% parts="modem"
export function setATPrefix(prefix: string): void {
AT_PREFIX = prefix;
}
/**
* Enable AT command debug.
*/
//% weight=1
//% blockId=modem_setDEBUG block="enable DEBUG %debug"
//% parts="modem"
export function enableDebug(debug: boolean = false): void {
DEBUG = debug;
}
/**
* Log a message to the USB console log.
* @param {string} prefix a prefix to be prepended to the line
* @param {string} message the message to log
*/
export function log(prefix: string, message: string): void {
if(TX == null) return;
basic.pause(100);
serial.resetSerial();
serial.writeLine(prefix + " " + message);
while (serial.busy()) basic.pause(10);
serial.redirect(TX, RX, BAUD);
basic.pause(100);
}
/**
* Log an array of messages to the USB console log.
* @param {string} prefix a prefix to be prepended to the line
* @param {string} messages the messages to log to the console
*/
export function logArray(prefix: string, messages: Array<string>): void {
if(TX == null) return;
basic.pause(100);
serial.resetSerial();
for (let i = 0; i < messages.length; i++) {
serial.writeLine(prefix + " (" + messages[i].length + ") " + messages[i]);
}
while (serial.busy()) basic.pause(10);
serial.redirect(TX, RX, BAUD);
basic.pause(100);
}
}