From 5412955a7b7ab2fa00c8419d6d3ce538465e50f8 Mon Sep 17 00:00:00 2001 From: David Betz Date: Sun, 25 Jan 2015 11:09:48 -0500 Subject: [PATCH] Add files for building for Windows and an updated Makefile that will build for Mac OS, Linux, and Windows. --- Makefile | 94 +++++++++++++-- enumcom.c | 141 ++++++++++++++++++++++ osint_mingw.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 549 insertions(+), 8 deletions(-) create mode 100755 enumcom.c create mode 100755 osint_mingw.c diff --git a/Makefile b/Makefile index 117dddb..e64d860 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,86 @@ -p1load: p1load.c ploader.c osint_linux.c - cc -Wall -DMACOSX -o $@ p1load.c ploader.c osint_linux.c - -run: p1load - ./p1load blink.binary -r -t - -clean: - rm -rf p1load +MKDIR=mkdir -p +RM=rm +CC=cc +ECHO=echo + +OS?=macosx + +ifeq ($(OS),linux) +CFLAGS+=-DLINUX +EXT= +OSINT=osint_linux +LIBS= +endif + +ifeq ($(OS),msys) +CFLAGS += -DMINGW +EXT=.exe +OSINT=osint_mingw enumcom +LIBS=-lsetupapi +endif + +ifeq ($(OS),macosx) +CFLAGS+=-DMACOSX +EXT= +OSINT=osint_linux +LIBS= +endif + +ifeq ($(OS),) +$(error OS not set) +endif + +SRCDIR=. +OBJDIR=obj/$(OS) +BINDIR=bin/$(OS) + +TARGET=$(BINDIR)/p1load$(EXT) + +HDRS=\ +ploader.h + +OBJS=\ +$(OBJDIR)/p1load.o \ +$(OBJDIR)/ploader.o \ +$(foreach x, $(OSINT), $(OBJDIR)/$(x).o) + +CFLAGS+=-Wall +LDFLAGS=$(CFLAGS) + +.PHONY: default +default: $(TARGET) + +DIRS=$(OBJDIR) $(BINDIR) + +$(TARGET): $(BINDIR) $(OBJDIR) $(OBJS) + @$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + @$(ECHO) link $@ + +$(OBJDIR)/%.o: $(SRCDIR)/%.c $(HDRS) $(OBJDIR) + @$(CC) $(CFLAGS) -c $< -o $@ + @$(ECHO) $(CC) $@ + +$(OBJDIR)/%.o: $(OBJDIR)/%.c $(HDRS) $(OBJDIR) + @$(CC) $(CFLAGS) -c $< -o $@ + @$(ECHO) $(CC) $@ + +.PHONY: bin2c +bin2c: $(BINDIR)/bin2c$(EXT) + +$(BINDIR)/bin2c$(EXT): $(SRCDIR)/tools/bin2c.c $(BINDIR) + @$(CC) $(CFLAGS) $(LDFLAGS) $(SRCDIR)/tools/bin2c.c -o $@ + @$(ECHO) cc $@ + +$(DIRS): + $(MKDIR) $@ + +.PHONY: clean +clean: + @$(RM) -f -r $(OBJDIR) + @$(RM) -f -r $(PROPOBJDIR) + @$(RM) -f -r $(BINDIR) + +.PHONY: +clean-all: clean + @$(RM) -f -r obj + @$(RM) -f -r bin diff --git a/enumcom.c b/enumcom.c new file mode 100755 index 0000000..9cacd62 --- /dev/null +++ b/enumcom.c @@ -0,0 +1,141 @@ +/************************************************************************* +* Derived from code by Zach Gorman with the following license: +* +* Serial port enumeration routines +* +* The EnumSerialPort function will populate an array of SSerInfo structs, +* each of which contains information about one serial port present in +* the system. Note that this code must be linked with setupapi.lib, +* which is included with the Win32 SDK. +* +* by Zach Gorman +* +* Copyright (c) 2002 Archetype Auction Software, Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following condition is +* met: Redistributions of source code must retain the above copyright +* notice, this condition and the following disclaimer. +* +* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL ARCHETYPE AUCTION SOFTWARE OR ITS +* AFFILIATES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#ifndef GUID_DEVINTERFACE_COMPORT +DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73); +#endif + +#ifdef MAIN +int CheckPort(const char* port, void* data) +{ + printf("Found %s\n", port); + return 0; +} + +int main(void) +{ + printf("serial_file returned %d\n", serial_find(NULL, CheckPort, NULL)); + return 0; +} +#endif + +int serial_find(const char* prefix, int (*check)(const char* port, void* data), void* data) +{ + GUID *guidDev = (GUID *) &GUID_DEVINTERFACE_COMPORT; + HDEVINFO hDevInfo = INVALID_HANDLE_VALUE; + SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL; + SP_DEVICE_INTERFACE_DATA ifcData; + DWORD dwDetDataSize; + int rc = -1; + BOOL bOk; + DWORD i; + + hDevInfo = SetupDiGetClassDevs( guidDev, + NULL, + NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE + ); + + if(hDevInfo == INVALID_HANDLE_VALUE) { + printf("error: SetupDiGetClassDevs failed. (err=%lx)\n", GetLastError()); + goto done; + } + + // Enumerate the serial ports + dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256; + pDetData = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(dwDetDataSize); + + ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + pDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + for (i = 0, bOk = TRUE; bOk; ++i) { + + // get the next device + bOk = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guidDev, i, &ifcData); + if (bOk) { + + // get the device details + SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)}; + bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo, &ifcData, pDetData, dwDetDataSize, NULL, &devdata); + if (bOk) { + TCHAR fname[256], desc[256]; + + // get some additional info + BOOL bSuccess = SetupDiGetDeviceRegistryProperty(hDevInfo, &devdata, SPDRP_FRIENDLYNAME, NULL, (PBYTE)fname, sizeof(fname), NULL) + && SetupDiGetDeviceRegistryProperty(hDevInfo, &devdata, SPDRP_DEVICEDESC, NULL, (PBYTE)desc, sizeof(desc), NULL); + if (bSuccess) { + char *comx, *p; + //printf("Device path: %s\n", pDetData->DevicePath); + //printf("Friendly name: %s\n", fname); + //printf("Description: %s\n", desc); + if ((comx = strchr(fname, '(')) != NULL) + ++comx; + else + comx = fname; + if ((p = strchr(comx, ')')) != NULL) + *p = '\0'; + if ((*check)(comx, data) == 0) { + rc = 0; + goto done; + } + } + + } + else { + printf("error: SetupDiGetDeviceInterfaceDetail failed. (err=%lx)\n", GetLastError()); + return 1; + } + } + else { + DWORD err = GetLastError(); + if (err != ERROR_NO_MORE_ITEMS) { + printf("error: SetupDiEnumDeviceInterfaces failed. (err=%lx)\n", err); + goto done; + } + } + } + +done: + if (pDetData != NULL) + free(pDetData); + if (hDevInfo != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList(hDevInfo); + + return rc; +} diff --git a/osint_mingw.c b/osint_mingw.c new file mode 100755 index 0000000..2dd0706 --- /dev/null +++ b/osint_mingw.c @@ -0,0 +1,322 @@ +/* + * osint_mingw.c - serial i/o routines for win32api via mingw + * + * Copyright (c) 2011 by Steve Denson. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include + +#include +#include +#include +#include "osint.h" + +static HANDLE hSerial = INVALID_HANDLE_VALUE; +static COMMTIMEOUTS original_timeouts; +static COMMTIMEOUTS timeouts; + +static void ShowLastError(void); + +/* normally we use DTR for reset but setting this variable to non-zero will use RTS instead */ +static int use_rts_for_reset = 0; + +void serial_use_rts_for_reset(int use_rts) +{ + use_rts_for_reset = use_rts; +} + +int serial_init(const char *port, unsigned long baud) +{ + char fullPort[20]; + + sprintf(fullPort, "\\\\.\\%s", port); + + hSerial = CreateFile( + fullPort, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (hSerial == INVALID_HANDLE_VALUE) + return FALSE; + + /* Set the baud rate. Always succeeds with mingw. */ + if (!serial_baud(baud)) { + serial_done(); + return 0; + } + + + GetCommTimeouts(hSerial, &original_timeouts); + timeouts = original_timeouts; + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + timeouts.WriteTotalTimeoutConstant = 1; + timeouts.WriteTotalTimeoutMultiplier = 1; + + /* setup device buffers */ + SetupComm(hSerial, 10000, 10000); + + /* purge any information in the buffer */ + PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); + + return TRUE; +} + +void serial_done(void) +{ + if (hSerial != INVALID_HANDLE_VALUE) { + FlushFileBuffers(hSerial); + CloseHandle(hSerial); + hSerial = INVALID_HANDLE_VALUE; + } +} + +/** + * change the baud rate of the serial port + * @param baud - baud rate + * @returns 1 for success and 0 for failure + */ +int serial_baud(unsigned long baud) +{ + DCB state; + GetCommState(hSerial, &state); + switch (baud) { + case 9600: + state.BaudRate = CBR_9600; + break; + case 19200: + state.BaudRate = CBR_19200; + break; + case 38400: + state.BaudRate = CBR_38400; + break; + case 57600: + state.BaudRate = CBR_57600; + break; + case 115200: + state.BaudRate = CBR_115200; + break; + default: + printf("Unsupported baudrate. Use "); + printf("115200, 57600, 38400, 19200, or 9600\n"); + printf("Setting default 115200\n"); + state.BaudRate = CBR_115200; + break; + } + + state.ByteSize = 8; + state.Parity = NOPARITY; + state.StopBits = ONESTOPBIT; + state.fOutxDsrFlow = FALSE; + state.fDtrControl = DTR_CONTROL_DISABLE; + state.fOutxCtsFlow = FALSE; + state.fRtsControl = RTS_CONTROL_DISABLE; + state.fInX = FALSE; + state.fOutX = FALSE; + state.fBinary = TRUE; + state.fParity = FALSE; + state.fDsrSensitivity = FALSE; + state.fTXContinueOnXoff = TRUE; + state.fNull = FALSE; + state.fAbortOnError = FALSE; + SetCommState(hSerial, &state); + + return 1; +} + +/** + * transmit a buffer + * @param buff - char pointer to buffer + * @param n - number of bytes in buffer to send + * @returns zero on failure + */ +int tx(uint8_t* buff, int n) +{ + DWORD dwBytes = 0; + if(!WriteFile(hSerial, buff, n, &dwBytes, NULL)){ + printf("Error writing port\n"); + ShowLastError(); + return 0; + } + return dwBytes; +} + +/** + * receive a buffer + * @param buff - char pointer to buffer + * @param n - number of bytes in buffer to read + * @returns number of bytes read + */ +int rx(uint8_t* buff, int n) +{ + DWORD dwBytes = 0; + SetCommTimeouts(hSerial, &original_timeouts); + if(!ReadFile(hSerial, buff, n, &dwBytes, NULL)){ + printf("Error reading port\n"); + ShowLastError(); + return 0; + } + return dwBytes; +} + +/** + * receive a buffer with a timeout + * @param buff - char pointer to buffer + * @param n - number of bytes in buffer to read + * @param timeout - timeout in milliseconds + * @returns number of bytes read or SERIAL_TIMEOUT + */ +int rx_timeout(uint8_t* buff, int n, int timeout) +{ + DWORD dwBytes = 0; + timeouts.ReadTotalTimeoutConstant = timeout; + SetCommTimeouts(hSerial, &timeouts); + if(!ReadFile(hSerial, buff, n, &dwBytes, NULL)){ + printf("Error reading port\n"); + ShowLastError(); + return 0; + } + return dwBytes > 0 ? dwBytes : SERIAL_TIMEOUT; +} + +/** + * hwreset ... resets Propeller hardware using DTR + * @returns void + */ +void hwreset(void) +{ + // reset then purge port + EscapeCommFunction(hSerial, use_rts_for_reset ? SETRTS : SETDTR); + Sleep(25); + PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); + EscapeCommFunction(hSerial, use_rts_for_reset ? CLRRTS : CLRDTR); + Sleep(90); + // Purge here after reset helps to get rid of buffered data. + PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); +} + +static unsigned long getms() +{ + LARGE_INTEGER ticksPerSecond; + LARGE_INTEGER tick; // A point in time + LARGE_INTEGER time; // For converting tick into real time + // get the high resolution counter's accuracy + QueryPerformanceFrequency(&ticksPerSecond); + if(ticksPerSecond.QuadPart < 1000) { + printf("Your system does not meet timer requirement. Try another computer. Exiting program.\n"); + exit(1); + } + // what time is it? + QueryPerformanceCounter(&tick); + time.QuadPart = (tick.QuadPart*1000/ticksPerSecond.QuadPart); + return (unsigned long)(time.QuadPart); +} + +/** + * sleep for ms milliseconds + * @param ms - time to wait in milliseconds + */ +void msleep(int ms) +{ + unsigned long t = getms(); + while((t+ms+10) > getms()) + ; +} + +static void ShowLastError(void) +{ + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, NULL); + printf(" %s\n", (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + exit(1); // exit on error +} + +/* escape from terminal mode */ +#define ESC 0x1b + +/* + * if "check_for_exit" is true, then + * a sequence EXIT_CHAR 00 nn indicates that we should exit + */ +#define EXIT_CHAR 0xff + +void terminal_mode(int check_for_exit, int pst_mode) +{ + int sawexit_char = 0; + int sawexit_valid = 0; + int exitcode = 0; + int continue_terminal = 1; + + while (continue_terminal) { + uint8_t buf[1]; + if (rx_timeout(buf, 1, 0) != SERIAL_TIMEOUT) { + if (sawexit_valid) { + exitcode = buf[0]; + continue_terminal = 0; + } + else if (sawexit_char) { + if (buf[0] == 0) { + sawexit_valid = 1; + } else { + putchar(EXIT_CHAR); + putchar(buf[0]); + fflush(stdout); + //sawexit_char = 0; + } + } + else if (check_for_exit && buf[0] == EXIT_CHAR) { + sawexit_char = 1; + } + else { + putchar(buf[0]); + if (pst_mode && buf[0] == '\r') + putchar('\n'); + fflush(stdout); + } + } + else if (kbhit()) { + if ((buf[0] = getch()) == ESC) + break; + tx(buf, 1); + } + } + + if (check_for_exit && sawexit_valid) { + exit(exitcode); + } +} +