//-----------------------------------------------------------------------------
// Copyright 2007 Jonathan Westhues
//
// This file is part of LDmicro.
//
// LDmicro is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// LDmicro is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with LDmicro. If not, see .
//------
//
// Miscellaneous utility functions that don't fit anywhere else. IHEX writing,
// verified memory allocator, other junk.
//-----------------------------------------------------------------------------
#include "linuxUI.h"
#include
#include
#include
#include "ldmicro.h"
using namespace std;
// We should display messages to the user differently if we are running
// interactively vs. in batch (command-line) mode.
BOOL RunningInBatchMode = FALSE;
// Allocate memory on a local heap
HANDLE MainHeap;
// Running checksum as we build up IHEX records.
static int IhexChecksum;
// Try to common a bit of stuff between the dialog boxes, since only one
// can be open at any time.
HWID OkButton;
HWID CancelButton;
BOOL DialogDone;
BOOL DialogCancel;
HFONT MyNiceFont;
HFONT MyFixedFont;
//-----------------------------------------------------------------------------
// printf-like debug function, to the Windows debug log.
//-----------------------------------------------------------------------------
void dbp(char *str, ...)
{
va_list f;
char buf[1024];
va_start(f, str);
vsprintf(buf, str, f);
OutputDebugString(buf);
OutputDebugString("\n");
}
//-----------------------------------------------------------------------------
// Wrapper for AttachConsole that does nothing running under = 0x500
// BOOL AttachConsoleDynamic(DWORD base)
// {
// typedef BOOL WINAPI fptr_acd(DWORD base);
// fptr_acd *fp;
// HMODULE hm = LoadLibrary("kernel32.dll");
// if(!hm) return FALSE;
// fp = (fptr_acd *)GetProcAddress(hm, "AttachConsole");
// if(!fp) return FALSE;
// return fp(base);
// }
//-----------------------------------------------------------------------------
// For error messages to the user; printf-like, to a message box.
//-----------------------------------------------------------------------------
void Error(char *str, ...)
{
va_list f;
char buf[1024];
va_start(f, str);
vsprintf(buf, str, f);
va_end(f);
if(RunningInBatchMode) {
printf("print batch mode");
/* Only required for windows
* AttachConsoleDynamic(ATTACH_PARENT_PROCESS);
*/
// Indicate that it's an error, plus the output filename
printf("compile error ('%s'): \n", CurrentCompileFile);
// The error message itself and an extra newline to be safe.
printf("%s\n", buf);
} else {
//HWND h = GetForegroundWindow();
// MessageBox(MainWindow, buf, _("LDmicro Error"), MB_OK | MB_ICONERROR);
}
}
//-----------------------------------------------------------------------------
// A standard format for showing a message that indicates that a compile
// was successful.
//-----------------------------------------------------------------------------
void CompileSuccessfulMessage(char *str)
{
if(RunningInBatchMode) {
char str[MAX_PATH+100];
printf("compiled okay, wrote '%s'\n", CurrentCompileFile);
//AttachConsoleDynamic(ATTACH_PARENT_PROCESS);
//HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
//DWORD written;
//riteFile(h, str, strlen(str), &written, NULL);
} else {
// MessageBox(MainWindow, str, _("Compile Successful"),
// MB_OK | MB_ICONINFORMATION);
}
}
//-----------------------------------------------------------------------------
// Check the consistency of the heap on which all the PLC program stuff is
// stored.
//-----------------------------------------------------------------------------
void CheckHeap(char *file, int line)
{
static unsigned int SkippedCalls;
static SDWORD LastCallTime;
SDWORD now = GetTickCount();
// It slows us down too much to do the check every time we are called;
// but let's still do the check periodically; let's do it every 70
// calls or every 20 ms, whichever is sooner.
if(SkippedCalls < 70 && (now - LastCallTime) < 20) {
SkippedCalls++;
return;
}
SkippedCalls = 0;
LastCallTime = now;
/*if(!HeapValidate(MainHeap, 0, NULL)) {
dbp("file %s line %d", file, line);
Error("Noticed memory corruption at file '%s' line %d.", file, line);
oops();
}*/
}
//-----------------------------------------------------------------------------
// Like malloc/free, but memsets memory allocated to all zeros. Also TODO some
// checking and something sensible if it fails.
//-----------------------------------------------------------------------------
void *CheckMalloc(size_t n)
{
ok();
void *p = HeapAlloc(MainHeap, HEAP_ZERO_MEMORY, n);
return p;
}
void CheckFree(void *p)
{
ok();
HeapFree(MainHeap, 0, p);
}
//-----------------------------------------------------------------------------
// Clear the checksum and write the : that starts an IHEX record.
//-----------------------------------------------------------------------------
void StartIhex(FILE *f)
{
fprintf(f, ":");
IhexChecksum = 0;
}
//-----------------------------------------------------------------------------
// Write an octet in hex format to the given stream, and update the checksum
// for the IHEX file.
//-----------------------------------------------------------------------------
void WriteIhex(FILE *f, BYTE b)
{
fprintf(f, "%02X", b);
IhexChecksum += b;
}
//-----------------------------------------------------------------------------
// Write the finished checksum to the IHEX file from the running sum
// calculated by WriteIhex.
//-----------------------------------------------------------------------------
void FinishIhex(FILE *f)
{
IhexChecksum = ~IhexChecksum + 1;
IhexChecksum = IhexChecksum & 0xff;
fprintf(f, "%02X\n", IhexChecksum);
}
//-----------------------------------------------------------------------------
// Create a window with a given client area.
//-----------------------------------------------------------------------------
/*HWID CreateWindowClient(GtkWindowType wType, GdkWindowTypeHint wthint, char *windowName,
int x, int y, int width, int height, HWND parent)
{
HWID h = gtk_window_new(wType);
gtk_window_set_title(GTK_WINDOW(h), windowName);
gtk_window_resize (GTK_WINDOW(h), width, height);
gtk_window_move(GTK_WINDOW(h), x, y);
gtk_window_set_type_hint (GTK_WINDOW(h), wthint);
// HWND h = CreateWindowEx(exStyle, className, windowName, style, x, y,
// width, height, parent, menu, instance, param);
// RECT r;
// GetClientRect(h, &r);
// width = width - (r.right - width);
// height = height - (r.bottom - height);
// SetWindowPos(h, HWND_TOP, x, y, width, height, 0);
return h;
}*/
//-----------------------------------------------------------------------------
// Window proc for the dialog boxes. This Ok/Cancel stuff is common to a lot
// of places, and there are no other callbacks from the children.
//-----------------------------------------------------------------------------
// static LRESULT CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam,
// LPARAM lParam)
// {
// switch (msg) {
// case WM_NOTIFY:
// break;
// case WM_COMMAND: {
// HWND h = (HWND)lParam;
// if(h == OkButton && wParam == BN_CLICKED) {
// DialogDone = TRUE;
// } else if(h == CancelButton && wParam == BN_CLICKED) {
// DialogDone = TRUE;
// DialogCancel = TRUE;
// }
// break;
// }
// case WM_CLOSE:
// case WM_DESTROY:
// DialogDone = TRUE;
// DialogCancel = TRUE;
// break;
// default:
// return DefWindowProc(hwnd, msg, wParam, lParam);
// }
// return 1;
// }
//-----------------------------------------------------------------------------
// Set the font of a control to a pretty proportional font (typ. Tahoma).
//-----------------------------------------------------------------------------
/*void NiceFont(HWID h)
{
GtkCssProvider *provider = gtk_css_provider_new ();
char *cssdata = new char[strlen(MyNiceFont->lpszFace) + 26];
int fontSize = 10;
sprintf(cssdata, "textview { font: %ipx %s; }", fontSize, MyNiceFont->lpszFace);
gtk_css_provider_load_from_data (provider, cssdata, -1, NULL);
delete cssdata;
gtk_style_context_add_provider (gtk_widget_get_style_context(h),
GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
// SendMessage(h, WM_SETFONT, (WPARAM)MyNiceFont, TRUE);
}
//-----------------------------------------------------------------------------
// Set the font of a control to a pretty fixed-width font (typ. Lucida
// Console).
//-----------------------------------------------------------------------------
void FixedFont(HWID h)
{
GtkCssProvider *provider = gtk_css_provider_new ();
char *cssdata = new char[strlen(MyFixedFont->lpszFace) + 26];
int fontSize = 10;
sprintf(cssdata, "textview { font: %ipx %s; }", fontSize, MyFixedFont->lpszFace);
gtk_css_provider_load_from_data (provider, cssdata, -1, NULL);
delete cssdata;
gtk_style_context_add_provider (gtk_widget_get_style_context(h),
GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
// SendMessage(h, WM_SETFONT, (WPARAM)MyFixedFont, TRUE);
}
*/
//-----------------------------------------------------------------------------
// Create our dialog box class, used for most of the popup dialogs.
//-----------------------------------------------------------------------------
void MakeDialogBoxClass(void)
{
// WNDCLASSEX wc;
// memset(&wc, 0, sizeof(wc));
// wc.cbSize = sizeof(wc);
// wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC |
// CS_DBLCLKS;
// wc.lpfnWndProc = (WNDPROC)DialogProc;
// wc.hInstance = Instance;
// wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
// wc.lpszClassName = "LDmicroDialog";
// wc.lpszMenuName = NULL;
// wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// wc.hIcon = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000),
// IMAGE_ICON, 32, 32, 0);
// wc.hIconSm = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000),
// IMAGE_ICON, 16, 16, 0);
// RegisterClassEx(&wc);
MyNiceFont = CreateFont(16, 0, 0, FW_REGULAR, FALSE, "Tahoma");
// if(!MyNiceFont)
// MyNiceFont = (HFONT)GetStockObject(SYSTEM_FONT);
MyFixedFont = CreateFont(14, 0, 0, FW_REGULAR, FALSE, "Lucida Console");
// if(!MyFixedFont)
// MyFixedFont = (HFONT)GetStockObject(SYSTEM_FONT);
}
//-----------------------------------------------------------------------------
// Map an I/O type to a string describing it. Used both in the on-screen
// list and when we write a text file to describe it.
//-----------------------------------------------------------------------------
char *IoTypeToString(int ioType)
{
switch(ioType) {
case IO_TYPE_DIG_INPUT: return _("digital in");
case IO_TYPE_DIG_OUTPUT: return _("digital out");
case IO_TYPE_INTERNAL_RELAY: return _("int. relay");
case IO_TYPE_UART_TX: return _("UART tx");
case IO_TYPE_UART_RX: return _("UART rx");
case IO_TYPE_PWM_OUTPUT: return _("PWM out");
case IO_TYPE_TON: return _("turn-on delay");
case IO_TYPE_TOF: return _("turn-off delay");
case IO_TYPE_RTO: return _("retentive timer");
case IO_TYPE_COUNTER: return _("counter");
case IO_TYPE_GENERAL: return _("general var");
case IO_TYPE_READ_ADC: return _("adc input");
default: return _("");
}
}
//-----------------------------------------------------------------------------
// Get a pin number for a given I/O; for digital ins and outs and analog ins,
// this is easy, but for PWM and UART this is forced (by what peripherals
// are available) so we look at the characteristics of the MCU that is in
// use.
//-----------------------------------------------------------------------------
void PinNumberForIo(char *dest, PlcProgramSingleIo *io)
{
if(!dest) return;
if(!io) {
strcpy(dest, "");
return;
}
int type = io->type;
if(type == IO_TYPE_DIG_INPUT || type == IO_TYPE_DIG_OUTPUT
|| type == IO_TYPE_READ_ADC)
{
int pin = io->pin;
if(pin == NO_PIN_ASSIGNED) {
strcpy(dest, _("(not assigned)"));
} else {
sprintf(dest, "%d", pin);
}
} else if(type == IO_TYPE_UART_TX && Prog.mcu) {
if(Prog.mcu->uartNeeds.txPin == 0) {
strcpy(dest, _(""));
} else {
sprintf(dest, "%d", Prog.mcu->uartNeeds.txPin);
}
} else if(type == IO_TYPE_UART_RX && Prog.mcu) {
if(Prog.mcu->uartNeeds.rxPin == 0) {
strcpy(dest, _(""));
} else {
sprintf(dest, "%d", Prog.mcu->uartNeeds.rxPin);
}
} else if(type == IO_TYPE_PWM_OUTPUT && Prog.mcu) {
if(Prog.mcu->pwmNeedsPin == 0) {
strcpy(dest, _(""));
} else {
sprintf(dest, "%d", Prog.mcu->pwmNeedsPin);
}
} else {
strcpy(dest, "");
}
}