summaryrefslogtreecommitdiff
path: root/ldmicro/miscutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ldmicro/miscutil.cpp')
-rw-r--r--ldmicro/miscutil.cpp413
1 files changed, 413 insertions, 0 deletions
diff --git a/ldmicro/miscutil.cpp b/ldmicro/miscutil.cpp
new file mode 100644
index 0000000..5806dc1
--- /dev/null
+++ b/ldmicro/miscutil.cpp
@@ -0,0 +1,413 @@
+//-----------------------------------------------------------------------------
+// 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 <http://www.gnu.org/licenses/>.
+//------
+//
+// Miscellaneous utility functions that don't fit anywhere else. IHEX writing,
+// verified memory allocator, other junk.
+//-----------------------------------------------------------------------------
+#include "linuxUI.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#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 <WinXP, so that
+// we still run (except for the console stuff) in earlier versions.
+//-----------------------------------------------------------------------------
+#define ATTACH_PARENT_PROCESS ((DWORD)-1) // defined in WinCon.h, but only if
+ // _WIN32_WINNT >= 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 _("<corrupt!>");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// 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, _("<no UART!>"));
+ } 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, _("<no UART!>"));
+ } else {
+ sprintf(dest, "%d", Prog.mcu->uartNeeds.rxPin);
+ }
+ } else if(type == IO_TYPE_PWM_OUTPUT && Prog.mcu) {
+ if(Prog.mcu->pwmNeedsPin == 0) {
+ strcpy(dest, _("<no PWM!>"));
+ } else {
+ sprintf(dest, "%d", Prog.mcu->pwmNeedsPin);
+ }
+ } else {
+ strcpy(dest, "");
+ }
+}