├── .gitignore ├── .gitmodules ├── .travis.yml ├── CHANGELOG.mkd ├── LICENSE ├── Makefile ├── README.mkd ├── arduino ├── .gitignore ├── Makefile └── baudsetter.ino ├── atcommander ├── atcommander.c └── atcommander.h ├── lpc17xx ├── .gdbinit ├── .gitignore ├── LPC17xx-baremetal.ld ├── LPC17xx-base.ld ├── LPC17xx-bootloader.ld ├── Makefile ├── flash.cfg ├── flash.sh ├── gdb.cfg ├── main.c └── startup.c ├── runtests.sh ├── script └── bootstrap.sh └── tests └── tests.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .DS_Store 3 | *~ 4 | *.bin 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lpc17xx/CDL"] 2 | path = lpc17xx/CDL 3 | url = https://github.com/openxc/nxp-cdl 4 | [submodule "lpc17xx/BSP"] 5 | path = lpc17xx/BSP 6 | url = https://github.com/openxc/nxp-bsp 7 | [submodule "lpc17xx/emqueue"] 8 | path = lpc17xx/emqueue 9 | url = https://github.com/openxc/emqueue 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | script: make test 5 | before_install: 6 | - sudo apt-get update -qq 7 | - script/bootstrap.sh 8 | -------------------------------------------------------------------------------- /CHANGELOG.mkd: -------------------------------------------------------------------------------- 1 | # AT-Commander Changelog 2 | 3 | ## v0.2 4 | 5 | * Add GET commands to retrieve name and unique device ID. 6 | 7 | ## v0.1 8 | 9 | * Initial release 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Ford Motor Company 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | INCLUDES = -I. -Iatcommander 3 | CFLAGS = $(INCLUDES) -c -w -Wall -Werror -g -ggdb 4 | LDFLAGS = 5 | LDLIBS = -lcheck 6 | 7 | TEST_DIR = tests 8 | 9 | # Guard against \r\n line endings only in Cygwin 10 | OSTYPE := $(shell uname) 11 | ifneq ($(OSTYPE),Darwin) 12 | OSTYPE := $(shell uname -o) 13 | ifeq ($(OSTYPE),Cygwin) 14 | TEST_SET_OPTS = igncr 15 | endif 16 | endif 17 | 18 | SRC = $(wildcard atcommander/*.c) 19 | OBJS = $(SRC:.c=.o) 20 | TEST_SRC = $(wildcard $(TEST_DIR)/*.c) 21 | TEST_OBJS = $(TEST_SRC:.c=.o) 22 | 23 | all: $(OBJS) 24 | 25 | test: $(TEST_DIR)/tests.bin 26 | @set -o $(TEST_SET_OPTS) >/dev/null 2>&1 27 | @export SHELLOPTS 28 | @sh runtests.sh $(TEST_DIR) 29 | 30 | $(TEST_DIR)/tests.bin: $(TEST_OBJS) $(OBJS) 31 | @mkdir -p $(dir $@) 32 | $(CC) $(LDFLAGS) $(CC_SYMBOLS) $(INCLUDES) -o $@ $^ $(LDLIBS) 33 | 34 | clean: 35 | rm -rf atcommander/*.o $(TEST_DIR)/*.o $(TEST_DIR)/*.bin 36 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | AT Commander 2 | ============ 3 | 4 | The AT Commander is a C library (with an optional C++ wrapper) for controller an 5 | embedded module that uses an AT command set. 6 | 7 | **Supported AT Platforms** 8 | 9 | * Roving Networks 10 | * RN-41 11 | * RN-42 12 | * Digi 13 | * XBee 14 | 15 | ## Firmware 16 | 17 | There are examples in this repository for a few platforms that you can flash to 18 | set the baud rate of an attached RN-42: 19 | 20 | * Arduino / chipKIT 21 | * LPC17xx 22 | 23 | ## C API Example 24 | 25 | 26 | For a full working example on the Arduion platform, see the `arduino` directory. 27 | 28 | A brief example: 29 | 30 | AtCommanderConfig config; 31 | config.platform = AT_PLATFORM_RN42; 32 | config.write_function = write_byte 33 | config.read_function = read_byte 34 | config.delay_function = delay; 35 | 36 | // Set the baud to 115200, if it's not already correct 37 | bool baud_set = at_commander_set_baud(&config, 115200); 38 | 39 | char device_id[20]; 40 | at_commander_get_device_id(&config, device_id, sizeof(device_id)); 41 | 42 | // Send an arbitrary "get" request: 43 | AtCommand my_get_command = { 44 | request_format: "GB", 45 | expected_response: NULL, 46 | error_response: "ERR" 47 | }; 48 | 49 | char response[25]; 50 | at_commander_get(config, &my_get_command, response, sizeof(response)); 51 | 52 | // Send an arbitrary "set" command, with arguments 53 | AtCommand my_set_command = { 54 | request_format: "SR,%s", 55 | expected_response: "AOK", 56 | error_response: "ERR" 57 | }; 58 | 59 | at_commander_set(config, &my_set_command, "Z"); 60 | 61 | 62 | ## C++ API Example 63 | 64 | TODO, might look like this: 65 | 66 | AtCommander commander(AT_PLATFORM_RN42, Serial.write, Serial.read, delay); 67 | commander.setBaud(115200); 68 | 69 | ## Testing 70 | 71 | The library includes a test suite that uses the `check` C unit test library. 72 | 73 | $ script/bootstrap.sh 74 | $ make test 75 | 76 | ## Authors 77 | 78 | Chris Peplin cpeplin@ford.com 79 | 80 | ## License 81 | 82 | Copyright (c) 2013 Ford Motor Company 83 | 84 | Licensed under the BSD license. 85 | -------------------------------------------------------------------------------- /arduino/.gitignore: -------------------------------------------------------------------------------- 1 | build-cli 2 | -------------------------------------------------------------------------------- /arduino/Makefile: -------------------------------------------------------------------------------- 1 | BOARD_TAG = mega_pic32 2 | ARDUINO_LIBS = atcommander 3 | 4 | USER_LIB_PATH = .. 5 | 6 | ifndef SERIAL_PORT 7 | SERIAL_PORT = /dev/ttyUSB* 8 | endif 9 | 10 | include $(ARDUINO_MAKEFILE_HOME)/chipKIT.mk 11 | -------------------------------------------------------------------------------- /arduino/baudsetter.ino: -------------------------------------------------------------------------------- 1 | #include "atcommander.h" 2 | 3 | #include "WProgram.h" 4 | #include 5 | 6 | extern const AtCommanderPlatform AT_PLATFORM_RN42; 7 | 8 | bool configured = false; 9 | AtCommanderConfig config; 10 | 11 | void write(void* device, uint8_t byte) { 12 | ((HardwareSerial*)device)->write(byte); 13 | } 14 | 15 | void begin(void* device, int baud) { 16 | ((HardwareSerial*)device)->begin(baud); 17 | } 18 | 19 | int read(void* device) { 20 | return ((HardwareSerial*)device)->read(); 21 | } 22 | 23 | void debug(const char* format, ...) { 24 | va_list args; 25 | va_start(args, format); 26 | char message[512]; 27 | vsnprintf(message, 512, format, args); 28 | Serial.print(message); 29 | va_end(args); 30 | } 31 | 32 | void setup() { 33 | Serial.begin(9600); 34 | Serial.println("About to change baud rate of RN-42 to 115200"); 35 | 36 | // Serial 1, pins 18 and 19 on the chipKIT, is where the RN-42 is attached 37 | config.platform = AT_PLATFORM_RN42; 38 | config.device = &Serial1; 39 | config.baud_rate_initializer = begin; 40 | config.write_function = write; 41 | config.read_function = read; 42 | config.delay_function = delay; 43 | config.log_function = debug; 44 | } 45 | 46 | void loop() { 47 | if(!configured) { 48 | if(at_commander_set_baud(&config, 115200)) { 49 | configured = true; 50 | at_commander_reboot(&config); 51 | } else { 52 | delay(5000); 53 | } 54 | } else { 55 | Serial1.println("Sending data over the RN-42 at 115200 baud!"); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /atcommander/atcommander.c: -------------------------------------------------------------------------------- 1 | #include "atcommander.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // TODO hard coded max of 128 - I've never seen one anywhere near this 8 | // long so we're probably OK. 9 | #define AT_COMMANDER_MAX_REQUEST_LENGTH 128 10 | #define AT_COMMANDER_DEFAULT_RESPONSE_DELAY_MS 100 11 | #define AT_COMMANDER_RETRY_DELAY_MS 50 12 | #define AT_COMMANDER_MAX_RESPONSE_LENGTH 8 13 | #define AT_COMMANDER_MAX_RETRIES 3 14 | 15 | #define at_commander_debug(config, ...) \ 16 | if(config->log_function != NULL) { \ 17 | config->log_function(__VA_ARGS__); \ 18 | config->log_function("\r\n"); \ 19 | } 20 | 21 | const AtCommanderPlatform AT_PLATFORM_RN42 = { 22 | AT_COMMANDER_DEFAULT_RESPONSE_DELAY_MS, 23 | rn42_baud_rate_mapper, 24 | { "$$$", "CMD" }, 25 | { "---\r", "END" }, 26 | { "SU,%d\r", "AOK" }, 27 | { "ST,%d\r", "AOK" }, 28 | { NULL, NULL }, 29 | { "R,1\r", "Reboot!" }, 30 | { "SN,%s\r", "AOK" }, 31 | { "S-,%s\r", "AOK" }, 32 | { "GN\r", NULL, "ERR" }, 33 | { "GB\r", NULL, "ERR" }, 34 | }; 35 | 36 | const AtCommanderPlatform AT_PLATFORM_XBEE = { 37 | 3000, 38 | xbee_baud_rate_mapper, 39 | { "+++", "OK" }, 40 | { NULL, NULL }, 41 | { "ATBD %d\r\n", "OK" }, 42 | { "ATWR\r\n", "OK" }, 43 | { NULL, NULL }, 44 | { NULL, NULL }, 45 | { NULL, NULL }, 46 | { NULL, NULL }, 47 | { NULL, NULL }, 48 | }; 49 | 50 | /** Private: Send an array of bytes to the AT device. 51 | */ 52 | void at_commander_write(AtCommanderConfig* config, const char* bytes, int size) { 53 | int i; 54 | if(config->write_function != NULL) { 55 | /* at_commander_debug(config, "tx: %s", bytes); */ 56 | for(i = 0; i < size; i++) { 57 | config->write_function(config->device, bytes[i]); 58 | } 59 | } 60 | } 61 | 62 | /** Private: If a delay function is available, delay the given time, otherwise 63 | * just continue. 64 | */ 65 | void at_commander_delay_ms(AtCommanderConfig* config, unsigned long ms) { 66 | if(config->delay_function != NULL) { 67 | config->delay_function(ms); 68 | } 69 | } 70 | 71 | /** Private: Read multiple bytes from Serial into the buffer. 72 | * 73 | * Continues to try and read each byte from Serial until a maximum number of 74 | * retries. 75 | * 76 | * Returns the number of bytes actually read - may be less than size. 77 | */ 78 | int at_commander_read(AtCommanderConfig* config, char* buffer, int size, 79 | int max_retries) { 80 | int bytes_read = 0; 81 | int retries = 0; 82 | bool sawCarraigeReturn = false; 83 | while(bytes_read < size && (max_retries == 0 || retries < max_retries)) { 84 | int byte = config->read_function(config->device); 85 | if(byte == -1) { 86 | at_commander_delay_ms(config, AT_COMMANDER_RETRY_DELAY_MS); 87 | retries++; 88 | } else if(byte != '\r' && byte != '\n') { 89 | buffer[bytes_read++] = byte; 90 | } 91 | 92 | if(bytes_read > 1) { 93 | if(byte == '\r') { 94 | sawCarraigeReturn = true; 95 | } else if(sawCarraigeReturn && byte == '\n') { 96 | break; 97 | } 98 | } 99 | } 100 | /* if(bytes_read > 0) { */ 101 | /* at_commander_debug(config, "rx: %s", buffer); */ 102 | /* } */ 103 | return bytes_read; 104 | } 105 | 106 | /** Private: Compare a response received from a device with some expected 107 | * output. 108 | * 109 | * Returns true if the reponse matches content and length, otherwise false. 110 | */ 111 | bool check_response(AtCommanderConfig* config, const char* response, 112 | int response_length, const char* expected, int expected_length) { 113 | if(response_length == expected_length && !strncmp(response, expected, 114 | expected_length)) { 115 | return true; 116 | } 117 | 118 | if(response_length != expected_length) { 119 | at_commander_debug(config, 120 | "Expected %d bytes in response but received %d", 121 | expected_length, response_length); 122 | } 123 | 124 | if(response_length > 0) { 125 | at_commander_debug(config, "Expected \"%s\" (%d bytes) in response " 126 | "but got \"%s\" (%d bytes)", expected, expected_length, 127 | response, response_length); 128 | } 129 | return false; 130 | } 131 | 132 | /** Private: Send an AT "get" query, read a response, and verify it doesn't match 133 | * any known errors. 134 | * 135 | * Returns true if the response isn't a known error state. 136 | */ 137 | int get_request(AtCommanderConfig* config, AtCommand* command, 138 | char* response_buffer, int response_buffer_length) { 139 | at_commander_write(config, command->request_format, 140 | strlen(command->request_format)); 141 | at_commander_delay_ms(config, config->platform.response_delay_ms); 142 | 143 | int bytes_read = at_commander_read(config, response_buffer, 144 | response_buffer_length - 1, AT_COMMANDER_MAX_RETRIES); 145 | response_buffer[bytes_read] = '\0'; 146 | 147 | if(strncmp(response_buffer, command->error_response, strlen(command->error_response))) { 148 | return bytes_read; 149 | } 150 | return -1; 151 | } 152 | 153 | 154 | /** Private: Send an AT command, read a response, and verify it matches the 155 | * expected value. 156 | * 157 | * Returns true if the response matches the expected. 158 | */ 159 | bool set_request(AtCommanderConfig* config, const char* command, const char* expected_response) { 160 | at_commander_write(config, command, strlen(command)); 161 | at_commander_delay_ms(config, config->platform.response_delay_ms); 162 | 163 | char response[AT_COMMANDER_MAX_RESPONSE_LENGTH]; 164 | int bytes_read = at_commander_read(config, response, strlen(expected_response), 165 | AT_COMMANDER_MAX_RETRIES); 166 | 167 | return check_response(config, response, bytes_read, expected_response, 168 | strlen(expected_response)); 169 | } 170 | 171 | bool at_commander_store_settings(AtCommanderConfig* config) { 172 | if(config->platform.store_settings_command.request_format != NULL 173 | && config->platform.store_settings_command.expected_response 174 | != NULL) { 175 | if(set_request(config, 176 | config->platform.store_settings_command.request_format, 177 | config->platform.store_settings_command.expected_response)) { 178 | at_commander_debug(config, "Stored settings into flash memory"); 179 | return true; 180 | } 181 | 182 | at_commander_debug(config, "Unable to store settings in flash memory"); 183 | return false; 184 | } 185 | return false; 186 | } 187 | 188 | bool at_commander_set(AtCommanderConfig* config, AtCommand* command, ...) { 189 | if(at_commander_enter_command_mode(config)) { 190 | va_list args; 191 | va_start(args, command); 192 | 193 | char request[AT_COMMANDER_MAX_REQUEST_LENGTH]; 194 | vsnprintf(request, AT_COMMANDER_MAX_REQUEST_LENGTH, command->request_format, args); 195 | 196 | va_end(args); 197 | 198 | if(set_request(config, request, command->expected_response)) { 199 | at_commander_store_settings(config); 200 | return true; 201 | } else { 202 | return false; 203 | } 204 | } else { 205 | at_commander_debug(config, 206 | "Unable to enter command mode, can't make set request"); 207 | return false; 208 | } 209 | } 210 | 211 | int at_commander_get(AtCommanderConfig* config, AtCommand* command, 212 | char* response_buffer, int response_buffer_length) { 213 | if(response_buffer == NULL || response_buffer_length <= 0) { 214 | at_commander_debug(config, "Buffer for query response is invalid"); 215 | return -1; 216 | } 217 | 218 | int bytes_read = -1; 219 | if(at_commander_enter_command_mode(config)) { 220 | bytes_read = get_request(config, command, response_buffer, 221 | response_buffer_length); 222 | } else { 223 | at_commander_debug(config, 224 | "Unable to enter command mode, can't get device name"); 225 | } 226 | return bytes_read; 227 | } 228 | 229 | /** Private: Change the baud rate of the UART interface and update the config 230 | * accordingly. 231 | * 232 | * This function does *not* attempt to change anything on the AT-command set 233 | * supporting device, it just changes the host interface. 234 | */ 235 | bool initialize_baud(AtCommanderConfig* config, int baud) { 236 | if(config->baud_rate_initializer != NULL) { 237 | at_commander_debug(config, "Initializing at baud %d", baud); 238 | config->baud_rate_initializer(config->device, baud); 239 | config->baud = baud; 240 | return true; 241 | } 242 | at_commander_debug(config, 243 | "No baud rate initializer set, can't change baud - trying anyway"); 244 | return false; 245 | } 246 | 247 | bool at_commander_enter_command_mode(AtCommanderConfig* config) { 248 | int baud_index; 249 | if(!config->connected) { 250 | for(baud_index = 0; baud_index < sizeof(VALID_BAUD_RATES) / 251 | sizeof(int); baud_index++) { 252 | initialize_baud(config, VALID_BAUD_RATES[baud_index]); 253 | at_commander_debug(config, "Attempting to enter command mode"); 254 | 255 | if(set_request(config, 256 | config->platform.enter_command_mode_command.request_format, 257 | config->platform.enter_command_mode_command.expected_response)) { 258 | config->connected = true; 259 | break; 260 | } 261 | } 262 | 263 | if(config->connected) { 264 | at_commander_debug(config, "Initialized UART and entered command " 265 | "mode at baud %d", config->baud); 266 | } else { 267 | at_commander_debug(config, 268 | "Unable to enter command mode at any baud rate"); 269 | } 270 | } 271 | return config->connected; 272 | } 273 | 274 | bool at_commander_exit_command_mode(AtCommanderConfig* config) { 275 | if(config->connected) { 276 | if(set_request(config, 277 | config->platform.exit_command_mode_command.request_format, 278 | config->platform.exit_command_mode_command.expected_response)) { 279 | at_commander_debug(config, "Switched back to data mode"); 280 | config->connected = false; 281 | return true; 282 | } else { 283 | at_commander_debug(config, "Unable to exit command mode"); 284 | return false; 285 | } 286 | } else { 287 | at_commander_debug(config, "Not in command mode"); 288 | return true; 289 | } 290 | } 291 | 292 | bool at_commander_reboot(AtCommanderConfig* config) { 293 | if(at_commander_enter_command_mode(config)) { 294 | if(set_request(config, 295 | config->platform.reboot_command.request_format, 296 | config->platform.reboot_command.expected_response)) { 297 | at_commander_debug(config, "Rebooted"); 298 | config->connected = false; 299 | } else { 300 | at_commander_debug(config, "Unable to reboot"); 301 | } 302 | return true; 303 | } else { 304 | at_commander_debug(config, "Unable to enter command mode, can't reboot"); 305 | return false; 306 | } 307 | } 308 | 309 | bool at_commander_set_configuration_timer(AtCommanderConfig* config, 310 | int timeout_s) { 311 | if(at_commander_enter_command_mode(config)) { 312 | char command[6]; 313 | sprintf(command, 314 | config->platform.set_configuration_timer_command.request_format, 315 | timeout_s); 316 | if(set_request(config, command, 317 | config->platform.set_configuration_timer_command.expected_response)) { 318 | at_commander_debug(config, "Changed configuration timer to %d", 319 | timeout_s); 320 | at_commander_store_settings(config); 321 | return true; 322 | } else { 323 | at_commander_debug(config, "Unable to change configuration timer"); 324 | return false; 325 | } 326 | } else { 327 | at_commander_debug(config, 328 | "Unable to enter command mode, can't set configuration timer"); 329 | return false; 330 | } 331 | } 332 | 333 | bool at_commander_set_baud(AtCommanderConfig* config, int baud) { 334 | int (*baud_rate_mapper)(int) = config->platform.baud_rate_mapper; 335 | if(at_commander_set(config, &config->platform.set_baud_rate_command, 336 | baud_rate_mapper(baud))) { 337 | at_commander_debug(config, "Changed device baud rate to %d", baud); 338 | config->device_baud = baud; 339 | return true; 340 | } else { 341 | at_commander_debug(config, "Unable to change device baud rate"); 342 | return false; 343 | } 344 | } 345 | 346 | bool at_commander_set_name(AtCommanderConfig* config, const char* name, 347 | bool serialized) { 348 | AtCommand* command = &config->platform.set_name_command; 349 | if(serialized) { 350 | at_commander_debug(config, 351 | "Appending unique serial number to end of name"); 352 | command = &config->platform.set_serialized_name_command; 353 | } 354 | if(at_commander_set(config, command, name)) { 355 | at_commander_debug(config, "Changed device name successfully to %s", 356 | name); 357 | return true; 358 | } 359 | return false; 360 | } 361 | 362 | int at_commander_get_device_id(AtCommanderConfig* config, char* buffer, 363 | int buflen) { 364 | return at_commander_get(config, &config->platform.get_device_id_command, 365 | buffer, buflen); 366 | } 367 | 368 | int at_commander_get_name(AtCommanderConfig* config, char* buffer, 369 | int buflen) { 370 | return at_commander_get(config, &config->platform.get_name_command, 371 | buffer, buflen); 372 | } 373 | 374 | int rn42_baud_rate_mapper(int baud) { 375 | int value; 376 | switch(baud) { 377 | case 1200: 378 | value = 12; 379 | break; 380 | case 2300: 381 | value = 23; 382 | break; 383 | case 4800: 384 | value = 48; 385 | break; 386 | case 9600: 387 | value = 96; 388 | break; 389 | case 19200: 390 | value = 19; 391 | break; 392 | case 38400: 393 | value = 28; 394 | break; 395 | case 57600: 396 | value = 57; 397 | break; 398 | case 115200: 399 | value = 11; 400 | break; 401 | case 230400: 402 | value = 23; 403 | break; 404 | case 460800: 405 | value = 46; 406 | break; 407 | case 921600: 408 | value = 92; 409 | break; 410 | } 411 | return value; 412 | } 413 | 414 | int xbee_baud_rate_mapper(int baud) { 415 | int value; 416 | switch(baud) { 417 | case 1200: 418 | value = 0; 419 | break; 420 | case 2300: 421 | value = 1; 422 | break; 423 | case 4800: 424 | value = 2; 425 | break; 426 | case 9600: 427 | value = 3; 428 | break; 429 | case 19200: 430 | value = 4; 431 | break; 432 | case 38400: 433 | value = 5; 434 | break; 435 | case 57600: 436 | value = 6; 437 | break; 438 | case 115200: 439 | value = 7; 440 | break; 441 | } 442 | return value; 443 | } 444 | -------------------------------------------------------------------------------- /atcommander/atcommander.h: -------------------------------------------------------------------------------- 1 | #ifndef _ATCOMMANDER_H_ 2 | #define _ATCOMMANDER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define AT_PLATFORM_RN41 AT_PLATFORM_RN42 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | static const int VALID_BAUD_RATES[] = {230400, 115200, 9600, 19200, 38400, 16 | 57600, 460800}; 17 | 18 | typedef struct { 19 | const char* request_format; 20 | const char* expected_response; 21 | const char* error_response; 22 | } AtCommand; 23 | 24 | typedef struct { 25 | int response_delay_ms; 26 | int (*baud_rate_mapper)(int baud); 27 | AtCommand enter_command_mode_command; 28 | AtCommand exit_command_mode_command; 29 | AtCommand set_baud_rate_command; 30 | AtCommand set_configuration_timer_command; 31 | AtCommand store_settings_command; 32 | AtCommand reboot_command; 33 | AtCommand set_name_command; 34 | AtCommand set_serialized_name_command; 35 | AtCommand get_name_command; 36 | AtCommand get_device_id_command; 37 | } AtCommanderPlatform; 38 | 39 | extern const AtCommanderPlatform AT_PLATFORM_RN42; 40 | extern const AtCommanderPlatform AT_PLATFORM_XBEE; 41 | 42 | typedef struct { 43 | AtCommanderPlatform platform; 44 | void (*baud_rate_initializer)(void* device, int); 45 | void (*write_function)(void* device, uint8_t); 46 | int (*read_function)(void* device); 47 | void (*delay_function)(unsigned long); 48 | void (*log_function)(const char*, ...); 49 | 50 | bool connected; 51 | int baud; 52 | int device_baud; 53 | void* device; 54 | } AtCommanderConfig; 55 | 56 | /** Public: Switch to command mode. 57 | * 58 | * If unable to determine the current baud rate and enter command mode, returns 59 | * false. 60 | * 61 | * Returns true if successful, or if already in command mode. 62 | */ 63 | bool at_commander_enter_command_mode(AtCommanderConfig* config); 64 | 65 | /** Public: Switch to data mode (from command mode). 66 | * 67 | * Returns true if the device was successfully switched to data mode. 68 | */ 69 | bool at_commander_exit_command_mode(AtCommanderConfig* config); 70 | 71 | /** Public: Soft-reboot the attached AT device. 72 | * 73 | * After rebooting, it's good practice to wait a few hundred ms for the device 74 | * to restart before trying any other commands. 75 | * 76 | * Returns true if the device was successfully rebooted. 77 | */ 78 | bool at_commander_reboot(AtCommanderConfig* config); 79 | 80 | /** Public: Change the UART baud rate of the attached AT device, regardless of 81 | * the current baud rate. 82 | * 83 | * Attempts to automatically determine the current baud rate in order to enter 84 | * command mode and change the baud rate. After updating the baud rate 85 | * successfully, it reboots the device. 86 | * 87 | * baud - the desired baud rate. 88 | * 89 | * Returns true if the baud rate was successfully changed. 90 | */ 91 | bool at_commander_set_baud(AtCommanderConfig* config, int baud); 92 | 93 | /** Public: Change the configuration timeout of the attached AT device. 94 | * 95 | * Attempts to automatically determine the current baud rate in order to enter 96 | * command mode and change the configuration timer (in seconds). A timeout of 0 97 | * means that remote configuration is not allowed (configuration is always 98 | * allowed via UART). 99 | * 100 | * timeout - the desired configuration timeout in seconds. 101 | * 102 | * Returns true if the configuration timer was successfully changed. 103 | */ 104 | bool at_commander_set_configuration_timer(AtCommanderConfig* config, int timeout_s); 105 | 106 | /** Public: Change the attached AT device's name. 107 | * 108 | * name - the desired name. 109 | * serialized - if true, will request the AT device append a unique serial 110 | * number to the end of the name (e.g. the last 2 digits of the MAC address). 111 | * 112 | * Returns true if the name was set successfully. 113 | */ 114 | bool at_commander_set_name(AtCommanderConfig* config, const char* name, 115 | bool serialized); 116 | 117 | /** Public: Retrieve the attached AT device's ID (usually MAC). 118 | * 119 | * buffer - a string buffer to store the retrieved device ID. 120 | * buflen - the length of the buffer. 121 | * 122 | * Returns the length of the response, or -1 if an error occurred. 123 | */ 124 | int at_commander_get_device_id(AtCommanderConfig* config, char* buffer, 125 | int buflen); 126 | 127 | /** Public: Retrieve the attached AT device's name. 128 | * 129 | * buffer - a string buffer to store the retrieved name. 130 | * buflen - the length of the buffer. 131 | * 132 | * Returns the length of the response, or -1 if an error occurred. 133 | */ 134 | int at_commander_get_name(AtCommanderConfig* config, char* buffer, 135 | int buflen); 136 | 137 | /** Public: Retrieve the attached AT device's name. 138 | * 139 | * buffer - a string buffer to store the retrieved name. 140 | * buflen - the length of the buffer. 141 | * 142 | * Returns the length of the response, or -1 if an error occurred. 143 | */ 144 | int at_commander_get_name(AtCommanderConfig* config, char* buffer, 145 | int buflen); 146 | 147 | /** Public: Send an AT "get" query, read a response, and verify it doesn't match 148 | * any known errors. 149 | * 150 | * Returns the length of the response, or -1 if an error occurred. 151 | */ 152 | int at_commander_get(AtCommanderConfig* config, AtCommand* command, 153 | char* response_buffer, int response_buffer_length); 154 | 155 | /** Public: Send an AT command, read a response, and verify it matches the 156 | * expected value. 157 | * 158 | * Returns true if the response matches the expected. 159 | */ 160 | bool at_commander_set(AtCommanderConfig* config, AtCommand* command, 161 | ...); 162 | 163 | int rn42_baud_rate_mapper(int baud); 164 | int xbee_baud_rate_mapper(int baud); 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif // _ATCOMMANDER_H_ 171 | -------------------------------------------------------------------------------- /lpc17xx/.gdbinit: -------------------------------------------------------------------------------- 1 | define hook-step 2 | mon cortex_m maskisr on 3 | end 4 | 5 | define hookpost-step 6 | mon cortex_m maskisr off 7 | end 8 | 9 | define hook-next 10 | mon cortex_m maskisr on 11 | end 12 | 13 | define hookpost-next 14 | mon cortex_m maskisr off 15 | end 16 | 17 | set remote hardware-breakpoint-limit 6 18 | set remote hardware-watchpoint-limit 4 19 | 20 | target remote localhost:3333 21 | 22 | echo .gdbinit for vi-firmware has been executed \n 23 | -------------------------------------------------------------------------------- /lpc17xx/.gitignore: -------------------------------------------------------------------------------- 1 | *.map 2 | *.elf 3 | -------------------------------------------------------------------------------- /lpc17xx/LPC17xx-baremetal.ld: -------------------------------------------------------------------------------- 1 | /* Start the user code at the top of flash - not compatible with the USB 2 | * bootloader. 3 | */ 4 | MEMORY 5 | { 6 | FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K 7 | RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = 0x7F38 8 | } 9 | 10 | GROUP(-lstdc++ -lsupc++ -lm -lc -lnosys -lgcc) 11 | INCLUDE "LPC17xx-base.ld" 12 | -------------------------------------------------------------------------------- /lpc17xx/LPC17xx-base.ld: -------------------------------------------------------------------------------- 1 | /* Linker script to place sections and symbol values. Should be used together 2 | * with other linker script that defines memory regions FLASH and RAM. 3 | * It references following symbols, which must be defined in code: 4 | * Reset_Handler : Entry of reset handler 5 | * 6 | * It defines following symbols, which code can use without definition: 7 | * __exidx_start 8 | * __exidx_end 9 | * __etext 10 | * __data_start__ 11 | * __preinit_array_start 12 | * __preinit_array_end 13 | * __init_array_start 14 | * __init_array_end 15 | * __fini_array_start 16 | * __fini_array_end 17 | * __data_end__ 18 | * __bss_start__ 19 | * __bss_end__ 20 | * __end__ 21 | * end 22 | * __HeapLimit 23 | * __StackLimit 24 | * __StackTop 25 | * __stack 26 | */ 27 | ENTRY(Reset_Handler) 28 | 29 | SECTIONS 30 | { 31 | .text : 32 | { 33 | KEEP(*(.isr_vector)) 34 | *(.text*) 35 | 36 | KEEP(*(.init)) 37 | KEEP(*(.fini)) 38 | 39 | /* .ctors */ 40 | *crtbegin.o(.ctors) 41 | *crtbegin?.o(.ctors) 42 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 43 | *(SORT(.ctors.*)) 44 | *(.ctors) 45 | 46 | /* .dtors */ 47 | *crtbegin.o(.dtors) 48 | *crtbegin?.o(.dtors) 49 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 50 | *(SORT(.dtors.*)) 51 | *(.dtors) 52 | 53 | *(.rodata*) 54 | 55 | KEEP(*(.eh_frame*)) 56 | } > FLASH 57 | 58 | .ARM.extab : 59 | { 60 | *(.ARM.extab* .gnu.linkonce.armextab.*) 61 | } > FLASH 62 | 63 | __exidx_start = .; 64 | .ARM.exidx : 65 | { 66 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 67 | } > FLASH 68 | __exidx_end = .; 69 | 70 | __etext = .; 71 | 72 | .data : AT (__etext) 73 | { 74 | __data_start__ = .; 75 | *(vtable) 76 | *(.data*) 77 | 78 | . = ALIGN(4); 79 | /* preinit data */ 80 | PROVIDE (__preinit_array_start = .); 81 | KEEP(*(.preinit_array)) 82 | PROVIDE (__preinit_array_end = .); 83 | 84 | . = ALIGN(4); 85 | /* init data */ 86 | PROVIDE (__init_array_start = .); 87 | KEEP(*(SORT(.init_array.*))) 88 | KEEP(*(.init_array)) 89 | PROVIDE (__init_array_end = .); 90 | 91 | 92 | . = ALIGN(4); 93 | /* finit data */ 94 | PROVIDE (__fini_array_start = .); 95 | KEEP(*(SORT(.fini_array.*))) 96 | KEEP(*(.fini_array)) 97 | PROVIDE (__fini_array_end = .); 98 | 99 | . = ALIGN(4); 100 | /* All data end */ 101 | __data_end__ = .; 102 | 103 | } > RAM 104 | 105 | .bss : 106 | { 107 | __bss_start__ = .; 108 | *(.bss*) 109 | *(COMMON) 110 | __bss_end__ = .; 111 | } > RAM 112 | 113 | .heap : 114 | { 115 | __end__ = .; 116 | end = __end__; 117 | *(.heap*) 118 | __HeapLimit = .; 119 | } > RAM 120 | 121 | /* .stack_dummy section doesn't contains any symbols. It is only 122 | * used for linker to calculate size of stack sections, and assign 123 | * values to stack symbols later */ 124 | .stack_dummy : 125 | { 126 | *(.stack) 127 | } > RAM 128 | 129 | /* Set stack top to end of RAM, and stack limit move down by 130 | * size of stack_dummy section */ 131 | __StackTop = ORIGIN(RAM) + LENGTH(RAM); 132 | __StackLimit = __StackTop - SIZEOF(.stack_dummy); 133 | PROVIDE(__stack = __StackTop); 134 | 135 | /* Check if data + heap + stack exceeds RAM limit */ 136 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") 137 | } 138 | -------------------------------------------------------------------------------- /lpc17xx/LPC17xx-bootloader.ld: -------------------------------------------------------------------------------- 1 | /* Start the user code 64KB into flash, as the USB bootloader expects. */ 2 | MEMORY 3 | { 4 | FLASH (rx) : ORIGIN = 0x10000, LENGTH = 512K - 0x10000 5 | RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = 0x7F38 6 | } 7 | 8 | GROUP(-lstdc++ -lsupc++ -lm -lc -lnosys -lgcc) 9 | INCLUDE "LPC17xx-base.ld" 10 | -------------------------------------------------------------------------------- /lpc17xx/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = baudsetter 2 | 3 | GCC_ARM_ON_PATH = $(shell command -v arm-none-eabi-gcc >/dev/null; echo $$?) 4 | 5 | ifneq ($(GCC_ARM_ON_PATH),0) 6 | GCC_BIN = ../dependencies/gcc-arm-embedded/bin/ 7 | endif 8 | 9 | ifndef JTAG_INTERFACE 10 | JTAG_INTERFACE = olimex-arm-usb-ocd 11 | endif 12 | 13 | OPENOCD_CONF_BASE = ../conf/openocd 14 | TARGET = $(BASE_TARGET)-lpc17xx 15 | CMSIS_PATH = ./CDL/CMSISv2p00_LPC17xx 16 | DRIVER_PATH = ./CDL/LPC17xxLib 17 | INCLUDE_PATHS = -I. -I../atcommander -I$(DRIVER_PATH)/inc -I$(CMSIS_PATH)/inc \ 18 | -IBSP -Iemqueue 19 | ifeq ($(BOOTLOADER), 1) 20 | LINKER_SCRIPT = LPC17xx-bootloader.ld 21 | else 22 | LINKER_SCRIPT = LPC17xx-baremetal.ld 23 | endif 24 | 25 | CC = $(GCC_BIN)arm-none-eabi-gcc 26 | AS_FLAGS = -c -mcpu=cortex-m3 -mthumb --defsym RAM_MODE=0 27 | CC_FLAGS = -c -fno-common -fmessage-length=0 -Wall -fno-exceptions \ 28 | -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections \ 29 | -Wno-char-subscripts -Wno-unused-but-set-variable -Werror -g -ggdb 30 | CC_SYMBOLS += -DTOOLCHAIN_GCC_ARM -D__LPC17XX__ -DBOARD=9 31 | 32 | AS = $(GCC_BIN)arm-none-eabi-as 33 | LD = $(GCC_BIN)arm-none-eabi-gcc 34 | LD_FLAGS = -mcpu=cortex-m3 -mthumb -Wl,--gc-sections 35 | LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc 36 | 37 | OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy 38 | 39 | LOCAL_C_SRCS = $(wildcard *.c) $(wildcard ../atcommander/*.c) 40 | LIB_C_SRCS += $(wildcard BSP/*.c) 41 | LIB_C_SRCS += $(wildcard BSP/LPCXpressoBase_RevB/*.c) 42 | LIB_C_SRCS += $(wildcard emqueue/*.c) 43 | LIB_C_SRCS += $(CMSIS_PATH)/src/core_cm3.c 44 | LIB_C_SRCS += $(CMSIS_PATH)/src/system_LPC17xx.c 45 | LIB_C_SRCS += $(wildcard $(DRIVER_PATH)/src/*.c) 46 | LOCAL_OBJ_FILES = $(LOCAL_C_SRCS:.c=.o) $(LIB_C_SRCS:.c=.o) 47 | 48 | BSP_EXISTS = $(shell test -e BSP/bsp.h; echo $$?) 49 | CDL_EXISTS = $(shell test -e CDL/README.mkd; echo $$?) 50 | ifneq ($(BSP_EXISTS),0) 51 | $(error BSP dependency is missing - did you run "git submodule init && git submodule update"?) 52 | endif 53 | ifneq ($(CDL_EXISTS),0) 54 | $(error CDL dependency is missing - did you run "git submodule init && git submodule update"?) 55 | endif 56 | 57 | all: $(PROJECT).bin 58 | 59 | clean: 60 | rm -f $(PROJECT).bin $(PROJECT).elf $(LOCAL_OBJ_FILES) *.o *.map 61 | 62 | .s.o: 63 | $(AS) $(CC_FLAGS) $(CC_SYMBOLS) -o $@ $< 64 | 65 | .c.o: 66 | $(CC) $(CC_FLAGS) $(CC_SYMBOLS) $(ONLY_C_FLAGS) $(INCLUDE_PATHS) -o $@ $< 67 | 68 | $(PROJECT).elf: $(LOCAL_OBJ_FILES) $(SYS_OBJECTS) 69 | $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $@ $^ $(LIBRARIES) $(LD_SYS_LIBS) $(LIBRARIES) $(LD_SYS_LIBS) 70 | 71 | $(PROJECT).bin: $(PROJECT).elf 72 | $(OBJCOPY) -O binary $< $@ 73 | 74 | flash: all 75 | @openocd -f flash.cfg 76 | 77 | gdb: all 78 | @openocd -f gdb.cfg 79 | -------------------------------------------------------------------------------- /lpc17xx/flash.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/olimex-arm-usb-ocd.cfg] 2 | source [find target/lpc1769.cfg] 3 | 4 | adapter_nsrst_assert_width 10 5 | reset_config srst_only 6 | adapter_khz 1200 7 | 8 | init 9 | sleep 100 10 | reset halt 11 | wait_halt 12 | sleep 100 13 | 14 | flash write_image erase baudsetter.bin 0 bin 15 | 16 | reset run 17 | shutdown 18 | -------------------------------------------------------------------------------- /lpc17xx/flash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Automate re-flashing an LPC17xx device running the USB bootloader from Linux. 4 | # 5 | # Example: 6 | # $ ./flash.sh /dev/sdc new-firmware.bin 7 | # 8 | 9 | DEVICE=$1 10 | FIRMWARE=$2 11 | 12 | echo "Deleting existing firmware..." 13 | sudo mdel -i $DEVICE ::/firmware.bin 14 | while [ $? != 0 ]; do 15 | sleep 2 16 | 17 | echo "Re-trying delete of existing firwmare..." 18 | sudo mdel -i $DEVICE ::/firmware.bin 19 | done 20 | 21 | echo "Copying new firmware..." 22 | sudo mcopy -i $DEVICE $FIRMWARE ::/firmware.bin 23 | echo "Done." 24 | -------------------------------------------------------------------------------- /lpc17xx/gdb.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/olimex-arm-usb-ocd.cfg] 2 | source [find target/lpc1769.cfg] 3 | 4 | adapter_nsrst_assert_width 10 5 | reset_config srst_only 6 | adapter_khz 1200 7 | 8 | init 9 | sleep 100 10 | reset halt 11 | wait_halt 12 | sleep 100 13 | -------------------------------------------------------------------------------- /lpc17xx/main.c: -------------------------------------------------------------------------------- 1 | #include "LPC17xx.h" 2 | #include "lpc17xx_uart.h" 3 | #include "lpc_types.h" 4 | #include "lpc17xx_timer.h" 5 | #include "lpc17xx_pinsel.h" 6 | #include "debug_frmwrk.h" 7 | #include "emqueue.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "atcommander.h" 14 | 15 | #define DESIRED_BAUDRATE 115200 16 | 17 | #define DELAY_TIMER LPC_TIM0 18 | #define UART1_DEVICE (LPC_UART_TypeDef*)LPC_UART1 19 | 20 | #define UART1_FUNCNUM 1 21 | #define UART1_PORTNUM 0 22 | #define UART1_TX_PINNUM 15 23 | #define UART1_RX_PINNUM 16 24 | #define UART1_FLOW_PORTNUM 2 25 | #define UART1_FLOW_FUNCNUM 2 26 | #define UART1_RTS1_PINNUM 2 27 | #define UART1_CTS1_PINNUM 7 28 | 29 | extern const AtCommanderPlatform AT_PLATFORM_RN42; 30 | 31 | QUEUE_DECLARE(uint8_t, 512); 32 | QUEUE_DEFINE(uint8_t); 33 | QUEUE_TYPE(uint8_t) receive_queue; 34 | 35 | void debug(const char* format, ...) { 36 | va_list args; 37 | va_start(args, format); 38 | char message[512]; 39 | vsnprintf(message, 512, format, args); 40 | _printf(message); 41 | va_end(args); 42 | } 43 | 44 | void delayMs(long unsigned int delayInMs) { 45 | TIM_TIMERCFG_Type delayTimerConfig; 46 | TIM_ConfigStructInit(TIM_TIMER_MODE, &delayTimerConfig); 47 | TIM_Init(DELAY_TIMER, TIM_TIMER_MODE, &delayTimerConfig); 48 | 49 | DELAY_TIMER->PR = 0x00; /* set prescaler to zero */ 50 | DELAY_TIMER->MR0 = (SystemCoreClock / 4) / (1000 / delayInMs); //enter delay time 51 | DELAY_TIMER->IR = 0xff; /* reset all interrupts */ 52 | DELAY_TIMER->MCR = 0x04; /* stop timer on match */ 53 | 54 | TIM_Cmd(DELAY_TIMER, ENABLE); 55 | 56 | /* wait until delay time has elapsed */ 57 | while (DELAY_TIMER->TCR & 0x01); 58 | } 59 | 60 | void configurePins() { 61 | PINSEL_CFG_Type PinCfg; 62 | 63 | PinCfg.Funcnum = UART1_FUNCNUM; 64 | PinCfg.OpenDrain = 0; 65 | PinCfg.Pinmode = 0; 66 | PinCfg.Portnum = UART1_PORTNUM; 67 | PinCfg.Pinnum = UART1_TX_PINNUM; 68 | PINSEL_ConfigPin(&PinCfg); 69 | PinCfg.Pinnum = UART1_RX_PINNUM; 70 | PINSEL_ConfigPin(&PinCfg); 71 | 72 | PinCfg.Portnum = UART1_FLOW_PORTNUM; 73 | PinCfg.Funcnum = UART1_FLOW_FUNCNUM; 74 | PinCfg.Pinnum = UART1_CTS1_PINNUM; 75 | PINSEL_ConfigPin(&PinCfg); 76 | PinCfg.Pinnum = UART1_RTS1_PINNUM; 77 | PINSEL_ConfigPin(&PinCfg); 78 | } 79 | 80 | void configureUart(void* device, int baud) { 81 | UART_CFG_Type UARTConfigStruct; 82 | UART_ConfigStructInit(&UARTConfigStruct); 83 | UARTConfigStruct.Baud_rate = baud; 84 | UART_Init(UART1_DEVICE, &UARTConfigStruct); 85 | 86 | UART_FIFO_CFG_Type fifoConfig; 87 | UART_FIFOConfigStructInit(&fifoConfig); 88 | UART_FIFOConfig(UART1_DEVICE, &fifoConfig); 89 | 90 | 91 | UART_IntConfig(UART1_DEVICE, UART_INTCFG_RBR, ENABLE); 92 | /* UART_IntConfig(UART1_DEVICE, UART_INTCFG_RLS, ENABLE); */ 93 | /* preemption = 1, sub-priority = 1 */ 94 | NVIC_SetPriority(UART1_IRQn, ((0x01<<3)|0x01)); 95 | NVIC_EnableIRQ(UART1_IRQn); 96 | 97 | UART_FullModemConfigMode(LPC_UART1, UART1_MODEM_MODE_AUTO_RTS, ENABLE); 98 | UART_FullModemConfigMode(LPC_UART1, UART1_MODEM_MODE_AUTO_CTS, ENABLE); 99 | 100 | UART_TxCmd(UART1_DEVICE, ENABLE); 101 | } 102 | 103 | void writeByte(void* device, uint8_t byte) { 104 | /* debug("Sending %d\r\n", byte); */ 105 | UART_SendByte(UART1_DEVICE, byte); 106 | } 107 | 108 | void handleReceiveInterrupt() { 109 | if(QUEUE_FULL(uint8_t, &receive_queue)) { 110 | // TODO why would it fill up? 111 | debug("Queue is full"); 112 | QUEUE_INIT(uint8_t, &receive_queue); 113 | } 114 | 115 | while(!QUEUE_FULL(uint8_t, &receive_queue)) { 116 | uint8_t byte; 117 | uint32_t received = UART_Receive(UART1_DEVICE, &byte, 1, NONE_BLOCKING); 118 | if(received > 0) { 119 | /* debug("Received %c\r\n", byte); */ 120 | QUEUE_PUSH(uint8_t, &receive_queue, byte); 121 | } else { 122 | break; 123 | } 124 | } 125 | } 126 | 127 | void UART1_IRQHandler() { 128 | uint32_t interruptSource = UART_GetIntId(UART1_DEVICE) 129 | & UART_IIR_INTID_MASK; 130 | switch(interruptSource) { 131 | case UART_IIR_INTID_RDA: 132 | case UART_IIR_INTID_CTI: 133 | handleReceiveInterrupt(); 134 | break; 135 | } 136 | } 137 | 138 | int readByte(void* device) { 139 | if(!QUEUE_EMPTY(uint8_t, &receive_queue)) { 140 | return QUEUE_POP(uint8_t, &receive_queue); 141 | } 142 | return -1; 143 | } 144 | 145 | int main (void) { 146 | debug_frmwrk_init(); 147 | _printf("About to change baud rate of RN-42 to %d\r\n", DESIRED_BAUDRATE); 148 | 149 | QUEUE_INIT(uint8_t, &receive_queue); 150 | 151 | bool configured = false; 152 | AtCommanderConfig config = {AT_PLATFORM_RN42}; 153 | 154 | config.baud_rate_initializer = configureUart; 155 | config.write_function = writeByte; 156 | config.read_function = readByte; 157 | config.delay_function = delayMs; 158 | config.log_function = debug; 159 | 160 | configurePins(); 161 | 162 | delayMs(1000); 163 | while(true) { 164 | if(!configured) { 165 | if(at_commander_set_baud(&config, DESIRED_BAUDRATE)) { 166 | configured = true; 167 | char name[20]; 168 | if(at_commander_get_name(&config, name, sizeof(name)) > 0) { 169 | _printf("Current name of device is %s\r\n", name); 170 | } else { 171 | _printf("Unable to get current device name\r\n"); 172 | } 173 | 174 | char device_id[20]; 175 | if(at_commander_get_device_id(&config, device_id, 176 | sizeof(device_id)) > 0) { 177 | _printf("Current ID of device is %s\r\n", device_id); 178 | } else { 179 | _printf("Unable to get current device ID\r\n"); 180 | } 181 | 182 | at_commander_set_name(&config, "AT-Commander", true); 183 | at_commander_reboot(&config); 184 | } else { 185 | delayMs(1000); 186 | } 187 | } else { 188 | char* message = "Sending data over the RN-42"; 189 | UART_Send(UART1_DEVICE, (uint8_t*)message, strlen(message), BLOCKING); 190 | } 191 | } 192 | 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /lpc17xx/startup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Derived from startup code originally published by Jakub Piotr Cłapa, 3 | * Copyright (c) 2010 LoEE under the new BSD license. 4 | * 5 | * See also: http://bitbucket.org/jpc/lpc1768/ 6 | * 7 | * NVIC handler names from NXP UM10360, comments taken from Opendous Inc. under 8 | * the following license: 9 | * 10 | * Permission to use, copy, modify, and distribute this software and its 11 | * documentation for any purpose and without fee is hereby granted, provided 12 | * that the above copyright notice appear in all copies and that both that the 13 | * copyright notice and this permission notice and warranty disclaimer appear in 14 | * supporting documentation, and that the name of the author not be used in 15 | * advertising or publicity pertaining to distribution of the software without 16 | * specific, written prior permission. 17 | 18 | * The author disclaim all warranties with regard to this software, including 19 | * all implied warranties of merchantability and fitness. In no event shall the 20 | * author be liable for any special, indirect or consequential damages or any 21 | * damages whatsoever resulting from loss of use, data or profits, whether in an 22 | * action of contract, negligence or other tortious action, arising out of or in 23 | * connection with the use or performance of this software. 24 | */ 25 | #include "LPC17xx.h" 26 | 27 | // Defined in linker script 28 | extern void __stack(void); 29 | extern uint32_t __etext; 30 | extern uint32_t __data_start__; 31 | extern uint32_t __data_end__; 32 | extern uint32_t __bss_start__; 33 | extern uint32_t __bss_end__; 34 | 35 | // Defined by user application 36 | extern int main (void); 37 | 38 | // Dummy handler. 39 | void Default_Handler (void) { while (1); } 40 | 41 | // Weakly bind all interrupt vectors to the dummy handler. 42 | void NMI_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 43 | void HardFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 44 | void MemManage_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 45 | void BusFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 46 | void UsageFault_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 47 | void SVC_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 48 | void DebugMon_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 49 | void PendSV_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 50 | void SysTick_Handler(void) __attribute__ ((weak, alias ("Default_Handler"))); 51 | void WDT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 52 | void TIMER0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 53 | void TIMER1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 54 | void TIMER2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 55 | void TIMER3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 56 | void UART0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 57 | void UART1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 58 | void UART2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 59 | void UART3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 60 | void PWM1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 61 | void I2C0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 62 | void I2C1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 63 | void I2C2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 64 | void SPI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 65 | void SSP0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 66 | void SSP1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 67 | void PLL0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 68 | void RTC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 69 | void EINT0_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 70 | void EINT1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 71 | void EINT2_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 72 | void EINT3_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 73 | void ADC_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 74 | void BOD_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 75 | void USB_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 76 | void CAN_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 77 | void DMA_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 78 | void I2S_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 79 | void ENET_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 80 | void RIT_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 81 | void MCPWM_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 82 | void QEI_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 83 | void PLL1_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 84 | void USBActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 85 | void CANActivity_IRQHandler(void) __attribute__ ((weak, alias ("Default_Handler"))); 86 | 87 | // The signature of Cortex-M3 interrupt handlers. 88 | typedef void (* const Interrupt_Handler_P)(void); 89 | 90 | // Forward declaration of Reset_Handler so we can refernece interrupt_vectors 91 | // when setting the VTOR in the handler. 92 | void Reset_Handler(void); 93 | 94 | // Interrupt vectors table 95 | __attribute__ ((section(".isr_vector"))) 96 | Interrupt_Handler_P interrupt_vectors[] = { 97 | &__stack, // the first word contains the initial 98 | // stack pointer the hardware loads it 99 | // to the SP register before the first 100 | // instruction 101 | // Standard Cortex-M3 interrupts: 102 | Reset_Handler, 103 | NMI_Handler, 104 | HardFault_Handler, 105 | MemManage_Handler, 106 | BusFault_Handler, 107 | UsageFault_Handler, 108 | 0, 109 | 0, 110 | 0, 111 | 0, 112 | SVC_Handler, 113 | DebugMon_Handler, 114 | 0, 115 | PendSV_Handler, 116 | SysTick_Handler, 117 | // LPC17xx Interrupts: Interrupt ID - Exception Number - Vector Offset - Description and Flags 118 | 119 | WDT_IRQHandler, // 0 16 0x40 WDT Watchdog Interrupt (WDINT) 120 | TIMER0_IRQHandler, // 1 17 0x44 Timer 0 Match 0 - 1 (MR0, MR1) 121 | // Capture 0 - 1 (CR0, CR1) 122 | TIMER1_IRQHandler, // 2 18 0x48 Timer 1 Match 0 - 2 123 | // (MR0, MR1, MR2), Capture 0 - 1 (CR0, CR1) 124 | TIMER2_IRQHandler, // 3 19 0x4C Timer 2 Match 0-3 125 | // Capture 0-1 126 | TIMER3_IRQHandler, // 4 20 0x50 Timer 3 Match 0-3 127 | // Capture 0-1 128 | UART0_IRQHandler, // 5 21 0x54 UART0 Rx Line Status (RLS) 129 | // Transmit Holding Register Empty (THRE) 130 | // Rx Data Available (RDA) 131 | // Character Time-out Indicator (CTI) 132 | // End of Auto-Baud (ABEO) 133 | // Auto-Baud Time-Out (ABTO) 134 | UART1_IRQHandler, // 6 22 0x58 UART1 Rx Line Status (RLS) 135 | // Transmit Holding Register Empty (THRE) 136 | // Rx Data Available (RDA) 137 | // Character Time-out Indicator (CTI) 138 | // Modem Control Change 139 | // End of Auto-Baud (ABEO) 140 | // Auto-Baud Time-Out (ABTO) 141 | UART2_IRQHandler, // 7 23 0x5C UART 2 Rx Line Status (RLS) 142 | // Transmit Holding Register Empty (THRE) 143 | // Rx Data Available (RDA) 144 | // Character Time-out Indicator (CTI) 145 | // End of Auto-Baud (ABEO) 146 | // Auto-Baud Time-Out (ABTO) 147 | UART3_IRQHandler, // 8 24 0x60 UART 3 Rx Line Status (RLS) 148 | // Transmit Holding Register Empty (THRE) 149 | // Rx Data Available (RDA) 150 | // Character Time-out Indicator (CTI) 151 | // End of Auto-Baud (ABEO) 152 | // Auto-Baud Time-Out (ABTO) 153 | PWM1_IRQHandler, // 9 25 0x64 PWM1 Match 0 - 6 of PWM1 154 | // Capture 0-1 of PWM1 155 | I2C0_IRQHandler, // 10 26 0x68 I2C0 SI (state change) 156 | I2C1_IRQHandler, // 11 27 0x6C I2C1 SI (state change) 157 | I2C2_IRQHandler, // 12 28 0x70 I2C2 SI (state change) 158 | SPI_IRQHandler, // 13 29 0x74 SPI SPI Interrupt Flag (SPIF) 159 | // Mode Fault (MODF) 160 | SSP0_IRQHandler, // 14 30 0x78 SSP0 Tx FIFO half empty of SSP0 161 | // Rx FIFO half full of SSP0 162 | // Rx Timeout of SSP0 163 | // Rx Overrun of SSP0 164 | SSP1_IRQHandler, // 15 31 0x7C SSP 1 Tx FIFO half empty 165 | // Rx FIFO half full 166 | // Rx Timeout 167 | // Rx Overrun 168 | PLL0_IRQHandler, // 16 32 0x80 PLL0 (Main PLL) PLL0 Lock (PLOCK0) 169 | RTC_IRQHandler, // 17 33 0x84 RTC Counter Increment (RTCCIF) 170 | // Alarm (RTCALF) 171 | EINT0_IRQHandler, // 18 34 0x88 External Interrupt External Interrupt 0 (EINT0) 172 | EINT1_IRQHandler, // 19 35 0x8C External Interrupt External Interrupt 1 (EINT1) 173 | EINT2_IRQHandler, // 20 36 0x90 External Interrupt External Interrupt 2 (EINT2) 174 | EINT3_IRQHandler, // 21 37 0x94 External Interrupt External Interrupt 3 (EINT3). 175 | // Note: EINT3 channel is shared with GPIO interrupts 176 | ADC_IRQHandler, // 22 38 0x98 ADC A/D Converter end of conversion 177 | BOD_IRQHandler, // 23 39 0x9C BOD Brown Out detect 178 | USB_IRQHandler, // 24 40 0xA0 USB USB_INT_REQ_LP, USB_INT_REQ_HP, USB_INT_REQ_DMA 179 | CAN_IRQHandler, // 25 41 0xA4 CAN CAN Common, CAN 0 Tx, CAN 0 Rx, CAN 1 Tx, CAN 1 Rx 180 | DMA_IRQHandler, // 26 42 0xA8 GPDMA IntStatus of DMA channel 0, IntStatus of DMA channel 1 181 | I2S_IRQHandler, // 27 43 0xAC I2S irq, dmareq1, dmareq2 182 | ENET_IRQHandler, // 28 44 0xB0 Ethernet WakeupInt, SoftInt, TxDoneInt, TxFinishedInt, TxErrorInt, 183 | // TxUnderrunInt, RxDoneInt, RxFinishedInt, RxErrorInt, RxOverrunInt. 184 | RIT_IRQHandler, // 29 45 0xB4 Repetitive Interrupt Timer (RITINT) 185 | MCPWM_IRQHandler, // 30 46 0xB8 Motor Control PWM IPER[2:0], IPW[2:0], ICAP[2:0], FES 186 | QEI_IRQHandler, // 31 47 0xBC Quadrature Encoder INX_Int, TIM_Int, VELC_Int, DIR_Int, ERR_Int, ENCLK_Int, 187 | // POS0_Int, POS1_Int, POS2_Int, REV_Int, POS0REV_Int, POS1REV_Int, POS2REV_Int 188 | PLL1_IRQHandler, // 32 48 0xC0 PLL1 (USB PLL) PLL1 Lock (PLOCK1) 189 | USBActivity_IRQHandler, // 33 49 0xC4 USB Activity Interrupt USB_NEED_CLK 190 | CANActivity_IRQHandler, // 34 50 0xC8 CAN Activity Interrupt CAN1WAKE, CAN2WAKE 191 | }; 192 | 193 | void Reset_Handler(void) { 194 | SystemInit(); 195 | // SystemInit clears the Vector Table Offset Register (VTOR) back to 0. If 196 | // we're running bare metal, the VTOR should be 0. If we're running behind the 197 | // USB bootloader, however, the interrupt vectors are not at to top of flash 198 | // anymore. We set the VTOR in the bootloader, but since we need to run 199 | // SystemInit here to power up the peripherals and clock, we have to re-set it 200 | // to the address of interrupt_vectors. 201 | SCB->VTOR = (uint32_t) interrupt_vectors; 202 | 203 | uint32_t *s, *d; 204 | // Copy initialization data to RAM (.data section) 205 | s = &__etext; 206 | d = &__data_start__; 207 | while (d < &__data_end__) *d++ = *s++; 208 | // Zero the remaining allocated RAM (.bss section) 209 | d = &__bss_start__; 210 | while (d < &__bss_end__) *d++ = 0; 211 | 212 | // Everything is ready. Run the user program. 213 | main(); 214 | while(1); // in case main() fails 215 | } 216 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | echo "Running unit tests:" 2 | 3 | for i in $1/*.bin 4 | do 5 | if test -f $i 6 | then 7 | if ./$i 8 | then 9 | echo $i PASS 10 | else 11 | echo "ERROR in test $i:" 12 | exit 1 13 | fi 14 | fi 15 | done 16 | 17 | echo "${txtbld}$(tput setaf 2)All unit tests passed.$(tput sgr0)" 18 | -------------------------------------------------------------------------------- /script/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | pushd $DIR/.. 7 | 8 | KERNEL=`uname` 9 | if [ ${KERNEL:0:7} == "MINGW32" ]; then 10 | OS="windows" 11 | elif [ ${KERNEL:0:6} == "CYGWIN" ]; then 12 | OS="cygwin" 13 | elif [ $KERNEL == "Darwin" ]; then 14 | OS="mac" 15 | else 16 | OS="linux" 17 | if ! command -v lsb_release >/dev/null 2>&1; then 18 | # Arch Linux 19 | if command -v pacman>/dev/null 2>&1; then 20 | sudo pacman -S lsb-release 21 | fi 22 | fi 23 | 24 | DISTRO=`lsb_release -si` 25 | fi 26 | 27 | _cygwin_error() { 28 | echo 29 | echo "${bldred}Missing \"$1\"${txtrst} - run the Cygwin installer again and select the base package set:" 30 | echo " $CYGWIN_PACKAGES" 31 | echo "After installing the packages, re-run this bootstrap script." 32 | die 33 | } 34 | 35 | if [ $OS == "cygwin" ] && ! command -v tput >/dev/null 2>&1; then 36 | _cygwin_error "ncurses" 37 | fi 38 | 39 | txtrst=$(tput sgr0) # reset 40 | bldred=${txtbld}$(tput setaf 1) 41 | bldgreen=${txtbld}$(tput setaf 2) 42 | 43 | die() { 44 | echo >&2 "${bldred}$@${txtrst}" 45 | exit 1 46 | } 47 | 48 | download() { 49 | url=$1 50 | filename=$2 51 | curl $url -L --O $filename 52 | } 53 | 54 | _wait() { 55 | if [ -z $CI ]; then 56 | echo "Press Enter when done" 57 | read 58 | fi 59 | } 60 | 61 | _install() { 62 | if [ $OS == "cygwin" ]; then 63 | _cygwin_error $1 64 | elif [ $OS == "mac" ]; then 65 | # brew exists with 1 if it's already installed 66 | set +e 67 | brew install $1 68 | set -e 69 | else 70 | if ! command -v lsb_release >/dev/null 2>&1; then 71 | echo 72 | echo "Missing $1 - install it using your distro's package manager or build from source" 73 | _wait 74 | else 75 | if [ $DISTRO == "arch" ]; then 76 | sudo pacman -S $1 77 | elif [ $DISTRO == "Ubuntu" ]; then 78 | sudo apt-get update -qq 79 | sudo apt-get install $1 -y 80 | else 81 | echo 82 | echo "Missing $1 - install it using your distro's package manager or build from source" 83 | _wait 84 | fi 85 | fi 86 | fi 87 | } 88 | 89 | CYGWIN_PACKAGES="git, curl, libsasl2, ca-certificates, ncurses, make, gcc4, check" 90 | 91 | if [ `id -u` == 0 ]; then 92 | die "Error: running as root - don't use 'sudo' with this script" 93 | fi 94 | 95 | if ! command -v curl >/dev/null 2>&1; then 96 | if [ $OS == "cygwin" ]; then 97 | _cygwin_error "curl" 98 | else 99 | _install curl 100 | fi 101 | fi 102 | 103 | echo "Storing all downloaded dependencies in the \"dependencies\" folder" 104 | 105 | DEPENDENCIES_FOLDER="dependencies" 106 | mkdir -p $DEPENDENCIES_FOLDER 107 | 108 | if [ $OS == "windows" ]; then 109 | die "Sorry, the bootstrap script for compiling from source doesn't support the Windows console - try Cygwin." 110 | fi 111 | 112 | if [ $OS == "mac" ] && ! command -v brew >/dev/null 2>&1; then 113 | echo "Installing Homebrew..." 114 | ruby -e "$(curl -fsSkL raw.github.com/mxcl/homebrew/go)" 115 | fi 116 | 117 | if ! command -v make >/dev/null 2>&1; then 118 | if [ $OS == "cygwin" ]; then 119 | _cygwin_error "make" 120 | elif [ $OS == "mac" ]; then 121 | echo "Missing 'make' - install the Xcode CLI tools" 122 | die 123 | else 124 | if [ $DISTRO == "arch" ]; then 125 | sudo pacman -S base-devel 126 | elif [ $DISTRO == "Ubuntu" ]; then 127 | sudo apt-get update -qq 128 | sudo apt-get install build-essential -y 129 | fi 130 | fi 131 | fi 132 | 133 | if ! command -v git >/dev/null 2>&1; then 134 | if [ $OS == "cygwin" ]; then 135 | _cygwin_error "git" 136 | elif [ $OS == "mac" ]; then 137 | _install git 138 | fi 139 | fi 140 | 141 | echo "Updating Git submodules..." 142 | 143 | # git submodule update is a shell script and expects some lines to fail 144 | set +e 145 | if ! git submodule update --init --quiet; then 146 | echo "Unable to update git submodules - try running \"git submodule update\" to see the full error" 147 | echo "If git complains that it \"Needed a single revision\", run \"rm -rf src/libs\" and then try the bootstrap script again" 148 | if [ $OS == "cygwin" ]; then 149 | echo "In Cygwin this may be true (ignore if you know ca-certifications is installed:" 150 | _cygwin_error "ca-certificates" 151 | fi 152 | die 153 | fi 154 | set -e 155 | 156 | echo "Installing dependencies for running test suite..." 157 | 158 | if [ $OS == "cygwin" ] && ! command -v ld >/dev/null 2>&1; then 159 | _cygwin_error "gcc4" 160 | fi 161 | 162 | if [ $OS == "mac" ]; then 163 | pushd $DEPENDENCIES_FOLDER 164 | LLVM_BASENAME=clang+llvm-3.2-x86_64-apple-darwin11 165 | LLVM_FILE=$LLVM_BASENAME.tar.gz 166 | LLVM_URL=http://llvm.org/releases/3.2/$LLVM_FILE 167 | 168 | if ! test -e $LLVM_FILE 169 | then 170 | echo "Downloading LLVM 3.2..." 171 | download $LLVM_URL $LLVM_FILE 172 | fi 173 | 174 | if ! test -d $LLVM_BASENAME 175 | then 176 | echo "Installing LLVM 3.2 to local folder..." 177 | tar -xzf $LLVM_FILE 178 | echo "LLVM 3.2 installed" 179 | fi 180 | 181 | popd 182 | fi 183 | 184 | if ! ld -lcheck -o /tmp/checkcheck 2>/dev/null; then 185 | echo "Installing the check unit testing library..." 186 | 187 | _install "check" 188 | fi 189 | 190 | # ARM / LPC17XX Dependencies 191 | 192 | if ! command -v arm-none-eabi-gcc >/dev/null 2>&1; then 193 | 194 | echo "Installing GCC for ARM Embedded..." 195 | 196 | GCC_ARM_BASENAME="gcc-arm-none-eabi-4_7-2012q4-20121208" 197 | if [ $OS == "linux" ]; then 198 | GCC_ARM_FILE="$GCC_ARM_BASENAME-linux.tar.bz2" 199 | elif [ $OS == "mac" ]; then 200 | GCC_ARM_FILE="$GCC_ARM_BASENAME-mac.tar.bz2" 201 | elif [ $OS == "cygwin" ]; then 202 | GCC_ARM_FILE="$GCC_ARM_BASENAME-win32.exe" 203 | fi 204 | 205 | GCC_ARM_URL="https://launchpad.net/gcc-arm-embedded/4.7/4.7-2012-q4-major/+download/$GCC_ARM_FILE" 206 | GCC_ARM_DIR="gcc-arm-embedded" 207 | 208 | pushd $DEPENDENCIES_FOLDER 209 | if ! test -e $GCC_ARM_FILE 210 | then 211 | download $GCC_ARM_URL $GCC_ARM_FILE 212 | fi 213 | 214 | mkdir -p $GCC_ARM_DIR 215 | pushd $GCC_ARM_DIR 216 | if [ $OS == "cygwin" ]; then 217 | chmod a+x ../$GCC_ARM_FILE 218 | INSTALL_COMMAND="cygstart.exe ../$GCC_ARM_FILE" 219 | PROGRAM_FILES_BASE="/cygdrive/c/" 220 | PROGRAM_FILES="Program Files" 221 | PROGRAM_FILES_64="Program Files (x86)" 222 | TRAILING_DIRNAME="GNU Tools ARM Embedded/4.7 2012q4/" 223 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES_64/$TRAILING_DIRNAME" 224 | if ! test -d "$GCC_INNER_DIR"; then 225 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES/$TRAILING_DIRNAME" 226 | fi 227 | else 228 | GCC_INNER_DIR="gcc-arm-none-eabi-4_7-2012q4" 229 | INSTALL_COMMAND="tar -xjf ../$GCC_ARM_FILE" 230 | fi 231 | 232 | if ! test -d "$GCC_INNER_DIR" 233 | then 234 | $INSTALL_COMMAND 235 | if [ $OS == "cygwin" ]; then 236 | echo -n "Press Enter when the GCC for ARM Embedded installer is finished" 237 | read 238 | fi 239 | fi 240 | 241 | if [ $OS == "cygwin" ]; then 242 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES_64/$TRAILING_DIRNAME" 243 | if ! test -d "$GCC_INNER_DIR"; then 244 | GCC_INNER_DIR="$PROGRAM_FILES_BASE/$PROGRAM_FILES/$TRAILING_DIRNAME" 245 | if ! test -d "$GCC_INNER_DIR"; then 246 | die "GCC for ARM isn't installed in the expected location." 247 | fi 248 | fi 249 | fi 250 | 251 | if ! test -d arm-none-eabi; then 252 | echo "Copying GCC binaries to local dependencies folder..." 253 | cp -R "$GCC_INNER_DIR"/* . 254 | fi 255 | 256 | popd 257 | popd 258 | 259 | fi 260 | 261 | if [ -z $CI ] && ! command -v openocd >/dev/null 2>&1; then 262 | 263 | ## Download OpenOCD for flashing ARM via JTAG 264 | pushd $DEPENDENCIES_FOLDER 265 | 266 | echo "Installing OpenOCD..." 267 | if [ $OS == "linux" ]; then 268 | _install "openocd" 269 | elif [ $OS == "mac" ]; then 270 | _install libftdi 271 | _install libusb 272 | set +e 273 | brew install --enable-ft2232_libftdi open-ocd 274 | set -e 275 | elif [ $OS == "cygwin" ]; then 276 | echo 277 | echo "Missing OpenOCD and it's not trivial to install in Windows - you won't be able to program the ARM platform (not required for the chipKIT translator)" 278 | fi 279 | popd 280 | fi 281 | 282 | FTDI_USB_DRIVER_PLIST=/System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist 283 | if [ -z $CI ] && [ $OS == "mac" ] && [ -e $FTDI_USB_DRIVER_PLIST ]; then 284 | if grep -q "Olimex OpenOCD JTAG A" $FTDI_USB_DRIVER_PLIST; then 285 | sudo sed -i "" -e "/Olimex OpenOCD JTAG A/{N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;d;}" $FTDI_USB_DRIVER_PLIST 286 | FTDI_USB_DRIVER_MODULE=/System/Library/Extensions/FTDIUSBSerialDriver.kext/ 287 | # Driver may not be loaded yet, but that's OK - don't exit on error. 288 | set +e 289 | sudo kextunload $FTDI_USB_DRIVER_MODULE 290 | set -e 291 | sudo kextload $FTDI_USB_DRIVER_MODULE 292 | fi 293 | fi 294 | 295 | popd 296 | 297 | echo 298 | echo "${bldgreen}All developer dependencies installed, ready to compile.$txtrst" 299 | -------------------------------------------------------------------------------- /tests/tests.c: -------------------------------------------------------------------------------- 1 | #include "atcommander.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | AtCommanderConfig config; 9 | 10 | void debug(const char* format, ...) { 11 | va_list args; 12 | va_start(args, format); 13 | vprintf(format, args); 14 | va_end(args); 15 | } 16 | 17 | void baud_rate_initializer(void* device, int baud) { 18 | } 19 | 20 | void mock_write(void* device, uint8_t byte) { 21 | } 22 | 23 | static char* read_message; 24 | static int read_message_length; 25 | static int read_index; 26 | 27 | int mock_read(void* device) { 28 | if(read_message != NULL && read_index < read_message_length) { 29 | return read_message[read_index++]; 30 | } 31 | return -1; 32 | } 33 | 34 | void setup() { 35 | config.platform = AT_PLATFORM_RN42; 36 | config.connected = false; 37 | config.baud = 9600; 38 | config.device_baud = 9600; 39 | config.baud_rate_initializer = baud_rate_initializer; 40 | config.write_function = mock_write; 41 | config.read_function = mock_read; 42 | config.delay_function = NULL; 43 | config.log_function = debug; 44 | 45 | read_message = NULL; 46 | read_message_length = 0; 47 | read_index = 0; 48 | } 49 | 50 | 51 | START_TEST (test_enter_command_mode_success) 52 | { 53 | char* response = "CMD\r\n"; 54 | read_message = response; 55 | read_message_length = 5; 56 | 57 | ck_assert(!config.connected); 58 | ck_assert(at_commander_enter_command_mode(&config)); 59 | ck_assert(config.connected); 60 | } 61 | END_TEST 62 | 63 | START_TEST (test_enter_command_mode_already_active) 64 | { 65 | read_message = NULL; 66 | read_message_length = 0; 67 | 68 | config.connected = true; 69 | ck_assert(at_commander_enter_command_mode(&config)); 70 | ck_assert(config.connected); 71 | } 72 | END_TEST 73 | 74 | START_TEST (test_enter_command_mode_at_baud) 75 | { 76 | char* response = "BADAAABADAAACMD\r\n"; 77 | read_message = response; 78 | read_message_length = 15; 79 | 80 | ck_assert(!config.connected); 81 | ck_assert(at_commander_enter_command_mode(&config)); 82 | ck_assert(config.connected); 83 | } 84 | END_TEST 85 | 86 | START_TEST (test_enter_command_mode_fail_bad_response) 87 | { 88 | char* response = "BAD\r\n"; 89 | read_message = response; 90 | read_message_length = 5; 91 | 92 | ck_assert(!config.connected); 93 | ck_assert(!at_commander_enter_command_mode(&config)); 94 | ck_assert(!config.connected); 95 | } 96 | END_TEST 97 | 98 | START_TEST (test_enter_command_mode_fail_no_response) 99 | { 100 | read_message = NULL; 101 | read_message_length = 0; 102 | 103 | ck_assert(!config.connected); 104 | ck_assert(!at_commander_enter_command_mode(&config)); 105 | ck_assert(!config.connected); 106 | } 107 | END_TEST 108 | 109 | START_TEST (test_exit_command_mode_success) 110 | { 111 | char* response = "END\r\n"; 112 | read_message = response; 113 | read_message_length = 5; 114 | 115 | config.connected = true; 116 | at_commander_exit_command_mode(&config); 117 | ck_assert(!config.connected); 118 | } 119 | END_TEST 120 | 121 | START_TEST (test_exit_command_mode_fail_bad_response) 122 | { 123 | char* response = "CMD"; 124 | read_message = response; 125 | read_message_length = 3; 126 | 127 | config.connected = true; 128 | at_commander_exit_command_mode(&config); 129 | ck_assert(config.connected); 130 | } 131 | END_TEST 132 | 133 | START_TEST (test_exit_command_mode_fail_no_response) 134 | { 135 | read_message = NULL; 136 | read_message_length = 0; 137 | 138 | config.connected = true; 139 | at_commander_exit_command_mode(&config); 140 | ck_assert(config.connected); 141 | } 142 | END_TEST 143 | 144 | START_TEST (test_exit_command_mode_already_done) 145 | { 146 | read_message = NULL; 147 | read_message_length = 0; 148 | 149 | ck_assert(!config.connected); 150 | at_commander_exit_command_mode(&config); 151 | ck_assert(!config.connected); 152 | } 153 | END_TEST 154 | 155 | START_TEST (test_set_baud_success) 156 | { 157 | char* response = "CMD\r\nAOK\r\n"; 158 | read_message = response; 159 | read_message_length = 10; 160 | 161 | ck_assert(!config.connected); 162 | ck_assert(at_commander_set_baud(&config, 115200)); 163 | ck_assert(config.connected); 164 | ck_assert_int_eq(config.device_baud, 115200); 165 | } 166 | END_TEST 167 | 168 | START_TEST (test_set_baud_bad_response) 169 | { 170 | char* response = "CMD\r\n?"; 171 | read_message = response; 172 | read_message_length = 6; 173 | 174 | ck_assert(!config.connected); 175 | ck_assert_int_ne(config.device_baud, 115200); 176 | ck_assert(!at_commander_set_baud(&config, 115200)); 177 | ck_assert(config.connected); 178 | ck_assert_int_ne(config.device_baud, 115200); 179 | } 180 | END_TEST 181 | 182 | START_TEST (test_set_baud_no_response) 183 | { 184 | char* response = "CMD\r\n"; 185 | read_message = response; 186 | read_message_length = 5; 187 | 188 | ck_assert(!config.connected); 189 | ck_assert_int_ne(config.device_baud, 115200); 190 | ck_assert(!at_commander_set_baud(&config, 115200)); 191 | ck_assert(config.connected); 192 | ck_assert_int_ne(config.device_baud, 115200); 193 | } 194 | END_TEST 195 | 196 | START_TEST (test_xbee_enter_command_mode_success) 197 | { 198 | config.platform = AT_PLATFORM_XBEE; 199 | char* response = "OK"; 200 | read_message = response; 201 | read_message_length = 2; 202 | 203 | ck_assert(!config.connected); 204 | ck_assert(at_commander_enter_command_mode(&config)); 205 | ck_assert(config.connected); 206 | } 207 | END_TEST 208 | 209 | START_TEST (test_get_device_id_success) 210 | { 211 | char* response = "CMD\r\n00066646C2AF\r\n"; 212 | read_message = response; 213 | read_message_length = 19; 214 | 215 | char device_id[20]; 216 | ck_assert(!config.connected); 217 | ck_assert(at_commander_get_device_id(&config, device_id, 218 | sizeof(device_id)) == 12); 219 | ck_assert(config.connected); 220 | ck_assert_str_eq(device_id, "00066646C2AF"); 221 | } 222 | END_TEST 223 | 224 | START_TEST (test_get_device_id_bad_response) 225 | { 226 | char* response = "CMD\r\nERR"; 227 | read_message = response; 228 | read_message_length = 8; 229 | 230 | char device_id[20]; 231 | ck_assert(!config.connected); 232 | ck_assert(at_commander_get_device_id(&config, device_id, sizeof(device_id)) == -1); 233 | ck_assert(config.connected); 234 | ck_assert_str_ne(device_id, "00066646C2AF"); 235 | } 236 | END_TEST 237 | 238 | START_TEST (test_get_device_id_no_response) 239 | { 240 | char* response = "CMD\r\n"; 241 | read_message = response; 242 | read_message_length = 5; 243 | 244 | char device_id[20]; 245 | ck_assert(!config.connected); 246 | ck_assert_int_eq(at_commander_get_device_id(&config, device_id, 247 | sizeof(device_id)), 0); 248 | ck_assert(config.connected); 249 | ck_assert_str_ne(device_id, "00066646C2AF"); 250 | } 251 | END_TEST 252 | 253 | START_TEST (test_get_name_success) 254 | { 255 | char* response = "CMD\r\nFOO\r\n"; 256 | read_message = response; 257 | read_message_length = 10; 258 | 259 | char name[20]; 260 | ck_assert(!config.connected); 261 | ck_assert(at_commander_get_name(&config, name, sizeof(name)) == 3); 262 | ck_assert(config.connected); 263 | ck_assert_str_eq(name, "FOO"); 264 | } 265 | END_TEST 266 | 267 | START_TEST (test_get_name_bad_response) 268 | { 269 | char* response = "CMD\r\nERR"; 270 | read_message = response; 271 | read_message_length = 8; 272 | 273 | char name[20]; 274 | ck_assert(!config.connected); 275 | ck_assert(at_commander_get_name(&config, name, sizeof(name)) == -1); 276 | ck_assert(config.connected); 277 | ck_assert_str_ne(name, "FOO"); 278 | } 279 | END_TEST 280 | 281 | START_TEST (test_get_name_no_response) 282 | { 283 | char* response = "CMD\r\n"; 284 | read_message = response; 285 | read_message_length = 5; 286 | 287 | char name[20]; 288 | ck_assert(!config.connected); 289 | ck_assert_int_eq(at_commander_get_name(&config, name, sizeof(name)), 0); 290 | ck_assert(config.connected); 291 | ck_assert_str_ne(name, "FOO"); 292 | } 293 | END_TEST 294 | 295 | Suite* suite(void) { 296 | Suite* s = suite_create("atcommander"); 297 | TCase *tc_enter_command_mode = tcase_create("enter_command_mode"); 298 | tcase_add_checked_fixture(tc_enter_command_mode, setup, NULL); 299 | tcase_add_test(tc_enter_command_mode, test_enter_command_mode_success); 300 | tcase_add_test(tc_enter_command_mode, test_enter_command_mode_already_active); 301 | tcase_add_test(tc_enter_command_mode, test_enter_command_mode_fail_bad_response); 302 | tcase_add_test(tc_enter_command_mode, test_enter_command_mode_fail_no_response); 303 | tcase_add_test(tc_enter_command_mode, test_enter_command_mode_at_baud); 304 | suite_add_tcase(s, tc_enter_command_mode); 305 | 306 | TCase *tc_exit_command_mode = tcase_create("exit_command_mode"); 307 | tcase_add_checked_fixture(tc_exit_command_mode, setup, NULL); 308 | tcase_add_test(tc_exit_command_mode, test_exit_command_mode_success); 309 | tcase_add_test(tc_exit_command_mode, test_exit_command_mode_fail_bad_response); 310 | tcase_add_test(tc_exit_command_mode, test_exit_command_mode_fail_no_response); 311 | tcase_add_test(tc_exit_command_mode, test_exit_command_mode_already_done); 312 | suite_add_tcase(s, tc_exit_command_mode); 313 | 314 | TCase *tc_set_baud = tcase_create("set_baud"); 315 | tcase_add_checked_fixture(tc_set_baud, setup, NULL); 316 | tcase_add_test(tc_set_baud, test_set_baud_success); 317 | tcase_add_test(tc_set_baud, test_set_baud_bad_response); 318 | tcase_add_test(tc_set_baud, test_set_baud_no_response); 319 | suite_add_tcase(s, tc_set_baud); 320 | 321 | TCase *tc_get_device_id = tcase_create("get_device_id"); 322 | tcase_add_checked_fixture(tc_get_device_id, setup, NULL); 323 | tcase_add_test(tc_get_device_id, test_get_device_id_success); 324 | tcase_add_test(tc_get_device_id, test_get_device_id_bad_response); 325 | tcase_add_test(tc_get_device_id, test_get_device_id_no_response); 326 | suite_add_tcase(s, tc_get_device_id); 327 | 328 | TCase *tc_get_name = tcase_create("get_name"); 329 | tcase_add_checked_fixture(tc_get_name, setup, NULL); 330 | tcase_add_test(tc_get_name, test_get_name_success); 331 | tcase_add_test(tc_get_name, test_get_name_bad_response); 332 | tcase_add_test(tc_get_name, test_get_name_no_response); 333 | suite_add_tcase(s, tc_get_name); 334 | 335 | TCase *tc_xbee = tcase_create("xbee"); 336 | tcase_add_checked_fixture(tc_xbee, setup, NULL); 337 | tcase_add_test(tc_xbee, test_xbee_enter_command_mode_success); 338 | suite_add_tcase(s, tc_xbee); 339 | return s; 340 | } 341 | 342 | int main(void) { 343 | int numberFailed; 344 | Suite* s = suite(); 345 | SRunner *sr = srunner_create(s); 346 | // Don't fork so we can actually use gdb 347 | srunner_set_fork_status(sr, CK_NOFORK); 348 | srunner_run_all(sr, CK_NORMAL); 349 | numberFailed = srunner_ntests_failed(sr); 350 | srunner_free(sr); 351 | return (numberFailed == 0) ? 0 : 1; 352 | } 353 | --------------------------------------------------------------------------------