/*************ArduSer.C******************* WIN USB COM Communication - Arduino (Fischetti P.) ****************************************/ #include #include #include #include #include #define BUFF_SIZE 128 const char* DRV_PATH = "\\\\.\\"; char portName[20]; #pragma comment(lib,"setupapi.lib") ////Dev-c++:Tools->Compiler Options->add the following when calling the linker: -lsetupapi int enmIno(); void dump(const unsigned char *data_buffer, const unsigned int length) { unsigned char byte; unsigned int i, j; for (i = 0; i < length; i++) { byte = data_buffer[i]; printf("%02x ", data_buffer[i]); // display byte in hex if (((i % 16) == 15) || (i == length - 1)) { for (j = 0; j < 15 - (i % 16); j++) printf(" "); printf("| "); for (j = (i - (i % 16)); j <= i; j++) { // display printable bytes from line byte = data_buffer[j]; if ((byte > 31) && (byte < 127)) // outside printable char range printf("%c", byte); else printf("."); } printf("\n"); // end of the dump line (each line 16 bytes) } // end if } // end for } void PrintError(const char *msg, DWORD err) { if (msg) fprintf(stderr, "%s%d\n", msg, err); //DWORD err = GetLastError(); LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR)&lpMsgBuf, 0, NULL); int sz = lstrlenW((LPWSTR)lpMsgBuf); char *buffer = (char *)calloc(sz + 1, sizeof(char)); wcstombs(buffer, (LPWSTR)lpMsgBuf, sz); fprintf(stderr, "WinAPI Last Error: %s", buffer); // Free the buffer. free(buffer); LocalFree(lpMsgBuf); } void strRemoveNL(char *buffer){ if(buffer) buffer[strcspn(buffer, "\r\n")] = 0; } void strClear(char *buffer){ memset(buffer,0,strlen(buffer)); } char dtTime[BUFF_SIZE]; char * getCurrdtTime(char *dtT) { SYSTEMTIME st; GetLocalTime(&st); sprintf(dtT, "[%d/%d/%d %d:%d:%d:%d] ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); return dtT; } HANDLE hComm=NULL; int quit(int iRet){ if(hComm){ hComm=NULL; CloseHandle(hComm); } return iRet; } void handler_quit(int signal){ fprintf(stderr,"BYE!\n"); quit(0); exit(0); } typedef int bool; #define true 1 #define false 0 bool setupComPort( DCB *dcb, DWORD baudRate, DWORD byteSize, BYTE parity, BYTE stopBits, DWORD fDtrControl) { dcb->DCBlength = sizeof(DCB); switch (baudRate) { case 110: dcb->BaudRate = CBR_110; break; case 300: dcb->BaudRate = CBR_300; break; case 600: dcb->BaudRate = CBR_600; break; case 1200: dcb->BaudRate = CBR_1200; break; case 2400: dcb->BaudRate = CBR_2400; break; case 4800: dcb->BaudRate = CBR_4800; break; case 9600: dcb->BaudRate = CBR_9600; break; case 14400: dcb->BaudRate = CBR_14400; break; case 19200: dcb->BaudRate = CBR_19200; break; case 38400: dcb->BaudRate = CBR_38400; break; case 57600: dcb->BaudRate = CBR_57600; break; case 115200: dcb->BaudRate = CBR_115200; break; case 256000: dcb->BaudRate = CBR_256000; break; default: fprintf(stderr, "Error on BaudRate\n"); return false; } dcb->ByteSize = byteSize; //8 data bits switch (parity) { case 0: dcb->Parity = NOPARITY; break; case 1: dcb->Parity = ODDPARITY; break; case 2: dcb->Parity = EVENPARITY; break; case 3: dcb->Parity = MARKPARITY; break; case 4: dcb->Parity = SPACEPARITY; break; default: fprintf(stderr, "Error on Parity\n"); return false; } switch (stopBits) { case 0: dcb->StopBits = ONESTOPBIT; break; case 1: dcb->StopBits = ONE5STOPBITS; break; case 2: dcb->StopBits = TWOSTOPBITS; break; default: fprintf(stderr, "Error on Stop Bit\n"); return false; } switch (fDtrControl) { case 0: dcb->fDtrControl = DTR_CONTROL_DISABLE; break; case 1: dcb->fDtrControl = DTR_CONTROL_ENABLE; break; case 2: dcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break; default: fprintf(stderr, "Error on DTR Control\n"); return false; } return true; } int help(char *proc) { fprintf(stderr,"\t*** RS232 <---> ARDUINO\t(By Fischetti P.) ***\n\n"); fprintf(stderr,"Syntax:\n\t"); fprintf(stderr," -pPORT [-l] [-mMode(R)] [-t]\n\nOptions: -pPortName (e.g.: COM6)\n\t -v Dump RX bytes\n\t" " -mMode is Trasmit(T)/Receive(R) or TrasmitReceive(X)\n\t -t Print TimeStamp\n\t -l enumerate Arduino COM Ports\n"); fprintf(stderr,"\t -oB(Binary Output)\n"); fprintf(stderr,"\t -nByteSize[8]\n"); fprintf(stderr,"\t -yParity\n"); fprintf(stderr,"\t\t[0]\tNo parity.\n"); fprintf(stderr,"\t\t1\tOdd parity.\n"); fprintf(stderr,"\t\t2\tEven parity.\n"); fprintf(stderr,"\t\t3\tMark parity.\n"); fprintf(stderr,"\t\t4\tSpace parity.\n"); fprintf(stderr,"\t -xStopBits\n"); fprintf(stderr,"\t\t[0]\t1 stop bit.\n"); fprintf(stderr,"\t\t1\t1.5 stop bits.\n"); fprintf(stderr,"\t\t1\t2 stop bits.\n"); fprintf(stderr,"\t -bBaudRate in bps:\n"); fprintf(stderr,"\t\t110"); fprintf(stderr,"\t300"); fprintf(stderr,"\t600"); fprintf(stderr,"\t1200\n"); fprintf(stderr,"\t\t2400"); fprintf(stderr,"\t4800"); fprintf(stderr,"\t[9600]"); fprintf(stderr,"\t14400\n"); fprintf(stderr,"\t\t19200"); fprintf(stderr,"\t38400"); fprintf(stderr,"\t57600"); fprintf(stderr,"\t115200\n"); fprintf(stderr,"\t\t128000"); fprintf(stderr,"\t256000\n"); fprintf(stderr,"\t -dDTRControl:\n"); fprintf(stderr,"\t\t0\tDisable.\n"); fprintf(stderr,"\t\t[1]\tEnable.\n"); fprintf(stderr,"\t\t2\tEnable HandShake.\n"); return -1; } typedef enum { None, RX, TX, X } enmMode; int main(int argc, char *argv[]) { // Handle to the Serial port BOOL Status; // Status DCB dcb = { 0 }; // Initializing DCB structure COMMTIMEOUTS timeouts = { 0 }; //Initializing timeouts structure char SerialBuffer[BUFF_SIZE] = { 0 }; //Buffer to send and receive data DWORD BytesWritten = 0; // No of bytes written to the port DWORD dwEventMask; // Event mask to trigger char ReadData; //temperory Character DWORD NoBytesRead; // Bytes read by ReadFile() unsigned char loop = 0; int i; DWORD errors; COMSTAT status; DWORD BaudRate = CBR_9600; BYTE ByteSize = 8; BYTE StopBits = ONESTOPBIT; BYTE Parity = NOPARITY; DWORD fDtrControl = DTR_CONTROL_ENABLE; bool bTimestamp = false,bDump=false; enmMode mode = RX; signal(SIGINT,handler_quit); signal(SIGABRT,handler_quit); int oBin=false; for (i = 1; i < argc; i++) { if (('-' == argv[i][0]) || ('/' == argv[i][0])) { char cp; cp = argv[i][1]; switch (cp) { case 'P': case 'p': { strcpy(portName, DRV_PATH); strncat(portName, &argv[i][2], 6); } break; case 'o': case 'O': { oBin = true; } break; case 't': case 'T': { bTimestamp = true; } break; case 'v': case 'V': { bDump = true; } break; case 'M': case 'm': { switch (tolower(argv[i][2])) { case 'r': mode = RX; break; case 't': { mode = TX; break; } case 'x': { mode = X; break; } break; default: help(argv[0]); return -1; } } break; case 'l': case 'L': { enmIno(); return 0; } break; case 'b': case 'B': { BaudRate = atoi(&argv[i][2]); } break; case 'n': case 'N': { ByteSize = atoi(&argv[i][2]); } break; case 'y': case 'Y': { Parity = atoi(&argv[i][2]); } break; case 'x': case 'X': { StopBits = atoi(&argv[i][2]); } break; case 'd': case 'D': { fDtrControl = atoi(&argv[i][2]); } break; case 'h': case '?': default: return help(argv[0]); } } } if (0 == strlen(portName)) { fprintf(stderr,"Error: Missing PortName!\n"); return -1; } if (oBin == true ) { if(!isatty(fileno(stdout))) setmode (fileno (stdout), O_BINARY); else{ fprintf(stderr, "ERROR In out Binary Mode: Missing Out File Redirect\n") ; return -1; } } //Open the serial com port hComm = CreateFile(portName, //friendly name GENERIC_READ | GENERIC_WRITE, // Read/Write Access 0, // No Sharing, ports cant be shared NULL, // No Security OPEN_EXISTING, // Open existing port only 0, // Non Overlapped I/O NULL); // Null for Comm Devices if (hComm == INVALID_HANDLE_VALUE) { PrintError("\n Port can't be opened ",GetLastError()); return quit(-1); } //Setting the Parameters for the SerialPort dcb.DCBlength = sizeof(dcb); Status = GetCommState(hComm, &dcb); //retreives the current settings if (Status == FALSE) { PrintError("\nError to Get the Com state ",GetLastError()); return quit(-1); } /* dcb.BaudRate = CBR_9600; //BaudRate = 9600 dcb.ByteSize = 8; //ByteSize = 8 dcb.StopBits = ONESTOPBIT; //StopBits = 1 dcb.Parity = NOPARITY; //Parity = None*/ //printf("X%d %d %d %d\n",dcb.BaudRate,dcb.ByteSize,dcb.StopBits,dcb.Parity ); setupComPort(&dcb, BaudRate, ByteSize, StopBits, Parity, fDtrControl); //printf("Y%d %d %d %d\n",dcb.BaudRate,dcb.ByteSize,dcb.StopBits,dcb.Parity ); fprintf(stderr,"[%s]BaudRate:%d ByteSize:%d StopBits:%d Parity:%d DTR Ctrl:%d.\n",(mode==RX?"RX":mode==X?"TXRX":mode==TX?"TX":"?"),dcb.BaudRate ,(int)dcb.ByteSize,(int)dcb.StopBits,(int)dcb.Parity, dcb.fDtrControl); Status = SetCommState(hComm, &dcb); if (Status == FALSE) { PrintError("\nError to Setting DCB Structure ",GetLastError()); return quit(-1); } //Setting Timeouts timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (SetCommTimeouts(hComm, &timeouts) == FALSE) { PrintError("\nError to Setting Time outs ",GetLastError()); return quit(-1); } fprintf(stderr,"Connected on port: %s\n",portName); //Writing data to Serial Port while (ClearCommError(hComm, &errors, &status)){ strClear(SerialBuffer); if(TX==mode || X == mode){ printf_s("#"); if(!fgets(SerialBuffer,sizeof(SerialBuffer),stdin)){ PrintError("\nFail to Written ",GetLastError()); continue; } //strRemoveNL(SerialBuffer); if(bDump) dump(SerialBuffer,sizeof(SerialBuffer)); Status = WriteFile(hComm,// Handle to the Serialport SerialBuffer, // Data to be written to the port strlen(SerialBuffer), // No of bytes to write into the port &BytesWritten, // No of bytes written to the port NULL); if (Status == FALSE) { PrintError("\nFail to Written ",GetLastError()); return quit(-1); } //print numbers of byte written to the serial port fprintf(stderr,"Number of bytes written to the serial port = %d\n", BytesWritten); } if(RX==mode || X == mode){ //Setting Receive Mask Status = SetCommMask(hComm, EV_RXCHAR); if (Status == FALSE) { PrintError("Error to in Setting CommMask ",GetLastError()); return quit(-1); } //Setting WaitComm() Event Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received if (Status == FALSE) { PrintError("Error! in Setting WaitCommEvent() ",GetLastError()); return quit(-1); } //Read data and store in a buffer strClear(SerialBuffer); loop=0; do { Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL); SerialBuffer[loop] = ReadData; ++loop; } while (NoBytesRead > 0); --loop; //Get Actual length of received data //fprintf(stderr,"nNumber of bytes received = %d\n", loop); strRemoveNL(SerialBuffer); if (true==bTimestamp) printf("%s ",getCurrdtTime(dtTime)); //if (strlen(SerialBuffer)>0) if(bDump) dump(SerialBuffer,sizeof(SerialBuffer)); if (oBin==true){ write(fileno(stdout),SerialBuffer,sizeof(SerialBuffer)); fprintf(stderr,"%s\n",SerialBuffer); } else printf("%s\n",SerialBuffer); fflush(stdout); } /*if (strlen(SerialBuffer)>0)*/ //dump(SerialBuffer,sizeof(SerialBuffer)); } quit(0); } /*************ROBOEX.C******************* Enumerate COM Devices (Fischetti P.) ****************************************/ #include #include #include #include #pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "setupapi.lib") #define MAX_NAME_PORTS 7 #define RegDisposition_OpenExisting (0x00000001) // open key only if exists #define CM_REGISTRY_HARDWARE (0x00000000) typedef DWORD (WINAPI* MYCM_Open_DevNode_Key) (DEVINST, REGSAM, ULONG, REGDISPOSITION, PHKEY, ULONG); /* CM_Open_DevNode_Key( _In_ DEVINST dnDevNode, _In_ REGSAM samDesired, _In_ ULONG ulHardwareProfile, _In_ REGDISPOSITION Disposition, _Out_ PHKEY phkDevice, _In_ ULONG ulFlags ); */ void PrintLastErr() { DWORD err = GetLastError(); LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL); printf("Error:%s", (LPCTSTR)lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); } /* * ArduScan * Sept 2011 by Bill Westfield ("WestfW") * * Scan a windows system and try to figure out which COM ports * look like they might be Arduinos. * * This is based on the article here: * http://www.codeproject.com/KB/system/serial_portsenum_fifo.aspx * by Vladimir Afanasyev, which explains how to use the device manager * API to enumerate all the COM ports on a system, and * these forum entries: * http://www.microchip.com/forums/tm.aspx?high=&m=559736&mpage=1#560699 * http://www.microchip.com/forums/tm.aspx?high=&m=364903&mpage=1#365029 * Which explain how to get the USB Vendor/Product info from the same api. * * Currently this is set up to run in a CMD or other shell window, and * writes its findings to stdout. * * * It should compile fine under cygin, including mingw versions: * * g++ -mno-cygwin ArduScan.cpp -lsetupapi -o ArduScan.exe * * * Vladimir's code is distributed according to the terms of "The Code * Project Open License (CPOL)" http://www.codeproject.com/info/cpol10.aspx * and Bill thinks that sounds fine, and doesn't add any terms for his own code. */ /* * USB Vendor IDs that are somewhat likely to be Arduinos. */ #define VENDOR_FTDI 0x403 #define VENDOR_ARDUINO 0x2341 /* * Vladamir's code for enumerating COM ports. Slightly modifed. */ #define MAX_NAME_PORTS 7 #define RegDisposition_OpenExisting (0x00000001) // open key only if exists #define CM_REGISTRY_HARDWARE (0x00000000) //typedef DWORD WINAPI(* CM_Open_DevNode_Key)(DWORD, DWORD, DWORD, DWORD, ::PHKEY, DWORD); HANDLE BeginEnumeratePorts(VOID) { BOOL guidTest=FALSE; DWORD RequiredSize=0; HDEVINFO DeviceInfoSet; char* buf; guidTest=SetupDiClassGuidsFromNameA("Ports",(LPGUID)0,0,&RequiredSize); if(RequiredSize < 1) return (HANDLE) -1; buf=(char *)malloc(RequiredSize*sizeof(GUID)); guidTest=SetupDiClassGuidsFromNameA( "Ports",(GUID *)buf,RequiredSize*sizeof(GUID),&RequiredSize); if(!guidTest) return (HANDLE) -1; DeviceInfoSet=SetupDiGetClassDevs( (GUID*)buf,NULL,NULL,DIGCF_PRESENT); free(buf); if(DeviceInfoSet == INVALID_HANDLE_VALUE) return (HANDLE) -1; return DeviceInfoSet; } BOOL EnumeratePortsNext(HANDLE DeviceInfoSet, LPTSTR lpBuffer, int *index) { static MYCM_Open_DevNode_Key OpenDevNodeKey=NULL; static HINSTANCE CfgMan; int res1; char DevName[MAX_NAME_PORTS]={0}; static int numDev=0; int numport; SP_DEVINFO_DATA DeviceInfoData={0}; DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA); if(!DeviceInfoSet || !lpBuffer) return -1; if(!OpenDevNodeKey) { CfgMan=LoadLibrary("cfgmgr32"); if(!CfgMan) return FALSE; OpenDevNodeKey=(MYCM_Open_DevNode_Key)GetProcAddress(CfgMan,"CM_Open_DevNode_Key"); if(!OpenDevNodeKey) { FreeLibrary(CfgMan); return FALSE; } } while(TRUE){ HKEY KeyDevice; DWORD len; res1=SetupDiEnumDeviceInfo( DeviceInfoSet,numDev,&DeviceInfoData); if(!res1) { SetupDiDestroyDeviceInfoList(DeviceInfoSet); FreeLibrary(CfgMan); OpenDevNodeKey=NULL; return FALSE; } res1=OpenDevNodeKey(DeviceInfoData.DevInst,KEY_QUERY_VALUE,0, RegDisposition_OpenExisting,&KeyDevice,CM_REGISTRY_HARDWARE); if(res1 != ERROR_SUCCESS) return FALSE; len=MAX_NAME_PORTS; res1=RegQueryValueEx( KeyDevice, // handle of key to query "portname", // address of name of value to query NULL, // reserved NULL, // address of buffer for value type (BYTE*)DevName, // address of data buffer &len // address of data buffer size ); RegCloseKey(KeyDevice); if(res1 != ERROR_SUCCESS) return FALSE; /* * Return the index too, so we can look up other info */ *index = numDev; numDev++; if(memcmp(DevName, "COM", 3)) continue; numport=atoi(DevName+3); if(numport > 0 && numport <= 256) { strcpy(lpBuffer,DevName); return TRUE; } FreeLibrary(CfgMan); OpenDevNodeKey=NULL; return FALSE; } } BOOL EndEnumeratePorts(HANDLE DeviceInfoSet) { if(SetupDiDestroyDeviceInfoList(DeviceInfoSet)) return TRUE; else return FALSE; } /* * End of Vladimir's code */ /* * Ascii HEX number to integer. Stop at invalid hex char */ int htoi(char *p) { int n = 0; while (*p) { char c = *p; if (c >= '0' && c <= '9') { n = n * 16 + (c - '0'); } else if (c >= 'a' && c <= 'z') { n = n * 16 + ((c+10) - 'a'); } else if (c >= 'A' && c <= 'Z') { n = n * 16 + ((c+10) - 'A'); } else break; p++; } return n; } /* * main program * enumerate the COM ports and split out any USB Vendor and Product info. * If the vendor is a likely Arduino (FTDI or Arduino), print out the info. */ int enmIno() { HANDLE h; SP_DEVINFO_DATA devInfo; int vendor, product; int deviceIndex; /* * Evil fixed-length strings; should allow variable length, * should allow univode. Bad non-windows programmer! */ char portname[50] = {0}; char idstring[100] = {0}; char infostring[100]; char *sernostr; char *infop = infostring; h = BeginEnumeratePorts(); if(INVALID_HANDLE_VALUE == h){ PrintLastErr(); return -1; } /* * h now has handle from deviceInfoSet (SetupDiGetClassDevs) */ devInfo.cbSize = sizeof(SP_DEVINFO_DATA); while (EnumeratePortsNext(h, portname, &deviceIndex)) { char *p; if(FALSE == SetupDiEnumDeviceInfo(h, deviceIndex, &devInfo)){ PrintLastErr(); return -1; } // SetupDiGetDeviceInstanceId(h, &devInfo, NULL, 0, &di_size); if(FALSE == SetupDiGetDeviceInstanceId(h, &devInfo, idstring, sizeof(idstring)-1, NULL)){ PrintLastErr(); return -1; } //printf("%s",idstring); infop = infostring; p = strstr(idstring, "VID_"); /* See if there is a vendor ID */ if (p) { vendor = htoi(p+4); } else { vendor = 0; } p = strstr(idstring, "PID_"); /* See if there is a Product ID */ if (p) { product = htoi(p+4); sernostr = p+9; /* The Serial number is everything past the PID */ } else { product = 0; sernostr = NULL; } //printf("%d %d %d",vendor,VENDOR_FTDI,VENDOR_ARDUINO); if (vendor == VENDOR_FTDI || vendor == VENDOR_ARDUINO) { // sprintf(infop, "Possible Arduino on %s, VID 0x%04x PID 0x%04x\n Serno %s", // portname, vendor, product, sernostr); // MessageBox(NULL, infop, "ArduinoFinder", 0); printf("Possible Arduino on %s, VID 0x%04x PID 0x%04x Serno %s\n", portname, vendor, product, sernostr); } else printf("Device on %s, VID 0x%04x PID 0x%04x Serno %s\n", portname, vendor, product, sernostr); } return 0; }