USB C++ bezel clock for WMC PVRs

Howdy everyone! I’m just gonna share a short datasheet of a project I was doing over the last two weeks or so for a Windows Media Center powered Personal Video Recorder.

What SparkFun products you’ll need:

[FTDI USB Cable (3.3v)

[7-Segment Serial Display

Connections:

Black → GND

Red → VCC

Orange → Rx

Visual Studio Win32 C++ Code

#pragma once
#include <windows.h>
SERVICE_STATUS Stat;
SERVICE_STATUS_HANDLE StatHandle;
void Event(DWORD e,DWORD ec=NULL){
	switch(e){
		case SERVICE_CONTROL_SHUTDOWN: 
		case SERVICE_CONTROL_STOP: 
			Stat.dwCurrentState=SERVICE_STOP_PENDING;
		break;
	}
	if(ec!=NULL){Stat.dwWin32ExitCode=ec;}
	SetServiceStatus(StatHandle,&Stat);
}
void O(HANDLE Port,char Data){
	if(Stat.dwCurrentState==SERVICE_RUNNING){
		DWORD tmp;
		if(WriteFile(Port,&Data,sizeof(Data),&tmp,NULL)){
			Sleep(5);
		}else{
			CloseHandle(Port);
			Event(SERVICE_CONTROL_STOP,ERROR_WRITE_FAULT);
		}
	}
}
void service(){
	StatHandle=RegisterServiceCtrlHandler("",(LPHANDLER_FUNCTION)Event);
	HANDLE Port=CreateFile("COM1",GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_DEVICE,NULL);
	SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);
	ZeroMemory(&Stat,sizeof(Stat));
	Stat.dwControlsAccepted=SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
	Stat.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
	Stat.dwWin32ExitCode=0;
	Stat.dwCurrentState=SERVICE_START_PENDING;SetServiceStatus(StatHandle,&Stat);
	if(Port==INVALID_HANDLE_VALUE){
		Stat.dwWin32ExitCode=ERROR_SERVICE_DISABLED;
	}else{
		DCB PortConfig;
		if(GetCommState(Port,&PortConfig)){
			PortConfig.BaudRate=CBR_9600;
			PortConfig.ByteSize=8;
			PortConfig.Parity=NOPARITY;
			PortConfig.StopBits=ONESTOPBIT;
			if(SetCommState(Port,&PortConfig)){
				SYSTEMTIME Now;
				Stat.dwCurrentState=SERVICE_RUNNING;SetServiceStatus(StatHandle,&Stat);
				do{GetLocalTime(&Now);
					O(Port,121);O(Port,0);
					O(Port,119);O(Port,16-(Now.wSecond%2*16));
					O(Port,48+(Now.wHour/10));
					O(Port,48+(Now.wHour%10));
					O(Port,48+(Now.wMinute/10));
					O(Port,48+(Now.wMinute%10));
				}while(Stat.dwCurrentState!=SERVICE_STOP_PENDING);
				O(Port,118);
			}
		}
		if(Port!=NULL){CloseHandle(Port);}
	}
	Stat.dwCurrentState=SERVICE_STOPPED;
	SetServiceStatus(StatHandle,&Stat);
}
int main(){ 
	SERVICE_TABLE_ENTRY ServiceTable;
	ServiceTable.lpServiceName="";
	ServiceTable.lpServiceProc=(LPSERVICE_MAIN_FUNCTION)service;
	StartServiceCtrlDispatcher(&ServiceTable);
	ExitProcess(0);
	return 0;
}

To create a new windows service, type this command in a command prompt running in administrator mode:

sc.exe create [service name] binPath= [path to exe]

Notes:

  • - The code above was witten and validated in Visual Studio 2005 in ANSI mode and should work unmodified on later versions (including the free express editions).
  • - I recommend running the resultant EXE under the LOCAL SERVICE account to protect the operating system the app runs on.

  • Have (Spark)Fun!](SparkFun 7-Segment Serial Display - Blue - COM-11442 - SparkFun Electronics)](FTDI Cable 5V VCC-3.3V I/O - DEV-09717 - SparkFun Electronics)