/** Process characters typed in by the user. Normally this will fire off a menu command, unless we are awaiting the user to enter a two-byte (four ascii character) short address or eight byte (16 ascii character) long address. @note: processCommand modifies variables shortAddressEntered and longAddressEntered @return the state to transition to next */ enum STATE processCommand(char cmd) { #define ESCAPE_KEY 0x1B if (cmd == ESCAPE_KEY) { printf("Resetting Command Line Interpreter\r\n"); commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; pendingState = STATE_IDLE; displayCommandLineInterfaceHelp(); return STATE_IDLE; } if (cmd == '\r') { printf("\r\n"); return STATE_IDLE; } if (commandLineInterfaceMode == CLI_MODE_NORMAL) { switch (cmd) { case '?': displayCommandLineInterfaceHelp(); return STATE_IDLE; case 'n': case 'N': return STATE_DISPLAY_NETWORK_INFORMATION; case 'r': case 'R': return STATE_INIT; case 'S': case 's': { printf("Enter short address of destination, for example '2F6B' or Escape key to exit\r\n"); commandLineInterfaceMode = CLI_MODE_ENTER_SHORT_ADDRESS; // Next, get a short address typed by the user pendingState = STATE_SEND_MESSAGE_VIA_SHORT_ADDRESS; // After a full short address has been entered return STATE_IDLE; } case 'L': case 'l': { printf("Enter long (MAC) address of destination, for example '00124B0012345678' or Escape key to exit\r\n"); commandLineInterfaceMode = CLI_MODE_ENTER_LONG_ADDRESS; pendingState = STATE_SEND_MESSAGE_VIA_LONG_ADDRESS; //when a full long address has been entered return STATE_IDLE; } case 'h': case 'H': { printf("Enter two byte short address to find, for example '2F6B' or press Escape key to exit\r\n"); commandLineInterfaceMode = CLI_MODE_ENTER_SHORT_ADDRESS; pendingState = STATE_FIND_VIA_SHORT_ADDRESS; //when a full short address has been entered return STATE_IDLE; } case 'j': case 'J': { printf("Enter eight byte long (MAC) address to find, for example '00124B0012345678' or press Escape key to exit\r\n"); commandLineInterfaceMode = CLI_MODE_ENTER_LONG_ADDRESS; pendingState = STATE_FIND_VIA_LONG_ADDRESS; //when a full long address has been entered return STATE_IDLE; } case 'v': case 'V': { printf("Module Version Information:\r\n"); if (sysVersion() == MODULE_SUCCESS) //gets the version string { displaySysVersion(); // Display the contents of the received SYS_VERSION } else { printf("ERROR\r\n"); } return STATE_IDLE; } /* Note: more commands can be added here */ default: printf("Unknown command %c\r\n", cmd); } return STATE_IDLE; } else if (commandLineInterfaceMode == CLI_MODE_ENTER_SHORT_ADDRESS) //accepts two hex numbers (4 ASCII characters) { if (IS_VALID_HEXADECIMAL_CHARACTER(cmd)) { TO_UPPER_CASE(cmd); printf("%c", cmd); //echo output cliInputBuffer[cliInputBufferIndex++] = (char) cmd; if (cliInputBufferIndex == 4) { cliInputBuffer[4] = 0; //null terminate it so we can treat it as a string //now attempt to convert it: long val = 0; errno = 0; // used in stdlib.h val = strtol(cliInputBuffer, NULL, 16); // Interpret the string as a hex number if (errno != 0) // Should have already been error checked, but validate anyway { printf("strtol parse error\r\n"); } else { //no errors shortAddressEntered = (uint16_t) val; printf("Short Address = 0x%04X\r\n", shortAddressEntered); //we're all done, so clear out buffers: commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; return STATE_VALID_SHORT_ADDRESS_ENTERED; } commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; return STATE_IDLE; } /* Continue, since our buffer isn't full yet - leave settings alone */ } else { /* not a hex number! */ printf("\r\nNumber must be in hex: 0..9 or a..f inclusive\r\nAborting\r\n"); displayCommandLineInterfaceHelp(); commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; } return STATE_IDLE; } else if (commandLineInterfaceMode == CLI_MODE_ENTER_LONG_ADDRESS) //accepts eight hex numbers (16 ASCII characters) { if (IS_VALID_HEXADECIMAL_CHARACTER(cmd)) { TO_UPPER_CASE(cmd); printf("%c", cmd); //echo output cliInputBuffer[cliInputBufferIndex++] = (char) cmd; /* To used a tokenized substring splitter method, add a '-' at the end of each 2 characters. */ if ((cliInputBufferIndex != 0) && ((cliInputBufferIndex+1) % 3 == 0) && (cliInputBufferIndex != 23)) { cliInputBuffer[cliInputBufferIndex++] = '-'; printf("-"); } if (cliInputBufferIndex == 23) { printf("\r\nParsed '%s' into:", cliInputBuffer); /* now attempt to convert it: */ char *substr = NULL; substr = strtok(cliInputBuffer,"-"); // Initialize string splitter /* Loops until there are no more substrings*/ uint8_t parsedMacIndex = 0; while(substr!=NULL) { /* Process the substring */ long val = 0; /* errno is used in stdlib.h to indicate a parse error */ errno = 0; val = strtol(substr, NULL, 16); // Interpret the string as a hex number if (errno != 0) // Should have already been error checked, but validate anyway { printf("strtol parse error\r\n"); commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; return STATE_IDLE; } else { //no errors longAddressEntered[parsedMacIndex] = (uint16_t) val; printf("%02X ", longAddressEntered[parsedMacIndex]); } parsedMacIndex++; substr = strtok(NULL,"-"); //Get the next substring } printf("\r\n"); /* Now we have the mac address */ if (!((longAddressEntered[0] == 0x00) && (longAddressEntered[1] == 0x12) && (longAddressEntered[2] == 0x4b))) printf("Warning - MAC does not have 00-12-4B as first three bytes!\r\n"); commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; return STATE_VALID_LONG_ADDRESS_ENTERED; } /* continue, since our buffer isn't full yet - leave settings alone */ } else { //not a hex number! printf("Number must be in hex: 0..9 or a..f inclusive\r\nAborting\r\n"); displayCommandLineInterfaceHelp(); commandLineInterfaceMode = CLI_MODE_NORMAL; cliInputBufferIndex = 0; } return STATE_IDLE; } return STATE_IDLE; }
static int utf16_to_shortname (int pass, const UTF16 *utf16, struct fs_fat_shortname *shortname) { int len; int a, b; int dotsfromstart = 0; int extdot = -1; unsigned long crc_num; int needs_long_filename; /* A sanity check of all pointers */ if ((shortname == 0) || (utf16 == 0) || (shortname->name == 0) || (shortname->ext == 0)) return 0; /* * Algorithm for a file name to end up in LFN entry: * a) If the file name length excluding ext is greater than 8 bytes. * b) If the file name has special chars that are not allowed in short file. * c) If a collision is detected (pass > 1). */ needs_long_filename = 0; /* Pass code is more than 1 means there was an entry found with the same * name, so now force the name conversion to use crc */ if (pass > 1) needs_long_filename = 1; /* calculate the length and other characteristics of the filename */ for (len = 0; utf16[len] != 0; len++) { /* If the char is out side the ASCII range then we need conversion */ if (utf16[len] > 0x7F) needs_long_filename = 1; } /* Prefill needed if our chars won't fill name, ext completely */ (void) memset (shortname->name, ' ', 8); (void) memset (shortname->ext, ' ', 3); /* check if it starts with '.' e.g. ".foo" */ if (utf16[0] == '.') { /* calculates the starting dots */ for (a = 0; a < len; a++) { if (utf16[a] != '.') break; dotsfromstart++; } } /* generating extension */ for (a = len; a > 0; a--) { if (utf16[a - 1] == '.') { /* check if we reach the starting dots, in this case this * is not an extension */ if (a == dotsfromstart) break; extdot = a - 1; for (b = 0; b < 3; a++) { /* Short file name should only have UPPER case chars. NTRES flag can be * used for conversion, but here instead of NTRES, it results into long * file name component */ UTF16 ch = (UTF16) TO_UPPER_CASE(utf16[a]); if (!ch) break; /* Space is an acceptable character in filename extension. * Spaces or invalid characters in filename are * handled by creating a long file name. * We are mapping any outside range char to _ */ if ((ch == ' ') || !is_valid_char_in_short_name (ch)) { needs_long_filename = 1; ch = '_'; } shortname->ext[b++] = (char) ch; } break; } } /* if extdot == -1 then the file doesn't have extension, * or the file name start from . */ if (extdot == -1) { if (len > 8) needs_long_filename = 1; } else { if (extdot > 8) needs_long_filename = 1; } /* Copy file name if conversion not needed. But if illegal chars * are there, then the conversion is needed. */ if (needs_long_filename == 0) { for (a = b = 0; b < 8; a++) { /* Upper case needed */ UTF16 ch = (UTF16) TO_UPPER_CASE (utf16[a]); if (!ch) break; if (ch == '.') { /* if we reach extension dot then stop */ if (a == extdot) break; } /* Space is an acceptable character in the filename. * Spaces or invalid characters in filename are * handled by creating a long file name. */ if ( (ch == ' ') || (!is_valid_char_in_short_name (ch))) { needs_long_filename = 1; break; } shortname->name[b++] = (char) ch; } } if (needs_long_filename == 1) { unsigned char cch; /* Came here means we cannot have the short file name, so generate * a unique file name by calculating the CRC of the long file name * if a collision happens then we can generate a different file * name which would be a very rare occurrence. */ /* Calculate CRC30 of the file name, so that it is unique */ crc_num = crc_30_step (pass, (byte*)utf16, (len * sizeof (*utf16) * 8)); /* Convert CRC to string for file name part */ for (a = 7; a >= 0; --a) { cch = crc_num & 0xF; cch += ((cch < 10) ? '0' : ('A' - 10)); shortname->name[a] = cch; crc_num >>= 4; } }