diff options
author | Rr42 | 2018-05-25 10:13:59 +0530 |
---|---|---|
committer | Rr42 | 2018-05-25 10:13:59 +0530 |
commit | f7669a3fcc87d4f6040257c3dd8708c263331458 (patch) | |
tree | 9eb6b47b5911eb1f13776caaa341aab40cabe5e7 /ldmicro/iolist.cpp | |
parent | 8deab843fa6d616086955702c77751f631badc0d (diff) | |
download | LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.tar.gz LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.tar.bz2 LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.zip |
Added all LDmicro filles to be ported
Diffstat (limited to 'ldmicro/iolist.cpp')
-rw-r--r-- | ldmicro/iolist.cpp | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/ldmicro/iolist.cpp b/ldmicro/iolist.cpp new file mode 100644 index 0000000..15b89c8 --- /dev/null +++ b/ldmicro/iolist.cpp @@ -0,0 +1,885 @@ +//----------------------------------------------------------------------------- +// 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/>. +//------ +// +// Routines to maintain the processor I/O list. Whenever the user changes the +// name of an element, rebuild the I/O list from the PLC program, so that new +// assigned names are automatically reflected in the I/O list. Also keep a +// list of old I/Os that have been deleted, so that if the user deletes a +// a name and then recreates it the associated settings (e.g. pin number) +// will not be forgotten. Also the dialog box for assigning I/O pins. +// Jonathan Westhues, Oct 2004 +//----------------------------------------------------------------------------- +#include <windows.h> +#include <commctrl.h> +#include <stdio.h> +#include <stdlib.h> + +#include "ldmicro.h" + +// I/O that we have seen recently, so that we don't forget pin assignments +// when we re-extract the list +#define MAX_IO_SEEN_PREVIOUSLY 512 +static struct { + char name[MAX_NAME_LEN]; + int type; + int pin; +} IoSeenPreviously[MAX_IO_SEEN_PREVIOUSLY]; +static int IoSeenPreviouslyCount; + +// stuff for the dialog box that lets you choose pin assignments +static BOOL DialogDone; +static BOOL DialogCancel; + +static HWND IoDialog; + +static HWND PinList; +static HWND OkButton; +static HWND CancelButton; + +// stuff for the popup that lets you set the simulated value of an analog in +static HWND AnalogSliderMain; +static HWND AnalogSliderTrackbar; +static BOOL AnalogSliderDone; +static BOOL AnalogSliderCancel; + + +//----------------------------------------------------------------------------- +// Append an I/O to the I/O list if it is not in there already. +//----------------------------------------------------------------------------- +static void AppendIo(char *name, int type) +{ + int i; + for(i = 0; i < Prog.io.count; i++) { + if(strcmp(Prog.io.assignment[i].name, name)==0) { + if(type != IO_TYPE_GENERAL && Prog.io.assignment[i].type == + IO_TYPE_GENERAL) + { + Prog.io.assignment[i].type = type; + } + // already in there + return; + } + } + if(i < MAX_IO) { + Prog.io.assignment[i].type = type; + Prog.io.assignment[i].pin = NO_PIN_ASSIGNED; + strcpy(Prog.io.assignment[i].name, name); + (Prog.io.count)++; + } +} + +//----------------------------------------------------------------------------- +// Move an I/O pin into the `seen previously' list. This means that if the +// user creates input Xasd, assigns it a pin, deletes, and then recreates it, +// then it will come back with the correct pin assigned. +//----------------------------------------------------------------------------- +static void AppendIoSeenPreviously(char *name, int type, int pin) +{ + if(strcmp(name+1, "new")==0) return; + + int i; + for(i = 0; i < IoSeenPreviouslyCount; i++) { + if(strcmp(name, IoSeenPreviously[i].name)==0 && + type == IoSeenPreviously[i].type) + { + if(pin != NO_PIN_ASSIGNED) { + IoSeenPreviously[i].pin = pin; + } + return; + } + } + if(IoSeenPreviouslyCount >= MAX_IO_SEEN_PREVIOUSLY) { + // maybe improve later; just throw away all our old information, and + // the user might have to reenter the pin if they delete and recreate + // things + IoSeenPreviouslyCount = 0; + } + + i = IoSeenPreviouslyCount; + IoSeenPreviously[i].type = type; + IoSeenPreviously[i].pin = pin; + strcpy(IoSeenPreviously[i].name, name); + IoSeenPreviouslyCount++; +} + +//----------------------------------------------------------------------------- +// Walk a subcircuit, calling ourselves recursively and extracting all the +// I/O names out of it. +//----------------------------------------------------------------------------- +static void ExtractNamesFromCircuit(int which, void *any) +{ + ElemLeaf *l = (ElemLeaf *)any; + + switch(which) { + case ELEM_PARALLEL_SUBCKT: { + ElemSubcktParallel *p = (ElemSubcktParallel *)any; + int i; + for(i = 0; i < p->count; i++) { + ExtractNamesFromCircuit(p->contents[i].which, + p->contents[i].d.any); + } + break; + } + case ELEM_SERIES_SUBCKT: { + ElemSubcktSeries *s = (ElemSubcktSeries *)any; + int i; + for(i = 0; i < s->count; i++) { + ExtractNamesFromCircuit(s->contents[i].which, + s->contents[i].d.any); + } + break; + } + case ELEM_CONTACTS: + switch(l->d.contacts.name[0]) { + case 'R': + AppendIo(l->d.contacts.name, IO_TYPE_INTERNAL_RELAY); + break; + + case 'Y': + AppendIo(l->d.contacts.name, IO_TYPE_DIG_OUTPUT); + break; + + case 'X': + AppendIo(l->d.contacts.name, IO_TYPE_DIG_INPUT); + break; + + default: + oops(); + break; + } + break; + + case ELEM_COIL: + AppendIo(l->d.coil.name, l->d.coil.name[0] == 'R' ? + IO_TYPE_INTERNAL_RELAY : IO_TYPE_DIG_OUTPUT); + break; + + case ELEM_TON: + case ELEM_TOF: + AppendIo(l->d.timer.name, which == ELEM_TON ? IO_TYPE_TON : + IO_TYPE_TOF); + break; + + case ELEM_RTO: + AppendIo(l->d.timer.name, IO_TYPE_RTO); + break; + + case ELEM_MOVE: + AppendIo(l->d.move.dest, IO_TYPE_GENERAL); + break; + + case ELEM_ADD: + case ELEM_SUB: + case ELEM_MUL: + case ELEM_DIV: + AppendIo(l->d.math.dest, IO_TYPE_GENERAL); + break; + + case ELEM_FORMATTED_STRING: + if(strlen(l->d.fmtdStr.var) > 0) { + AppendIo(l->d.fmtdStr.var, IO_TYPE_UART_TX); + } + break; + + case ELEM_UART_SEND: + AppendIo(l->d.uart.name, IO_TYPE_UART_TX); + break; + + case ELEM_UART_RECV: + AppendIo(l->d.uart.name, IO_TYPE_UART_RX); + break; + + case ELEM_SET_PWM: + AppendIo(l->d.setPwm.name, IO_TYPE_PWM_OUTPUT); + break; + + case ELEM_CTU: + case ELEM_CTD: + case ELEM_CTC: + AppendIo(l->d.counter.name, IO_TYPE_COUNTER); + break; + + case ELEM_READ_ADC: + AppendIo(l->d.readAdc.name, IO_TYPE_READ_ADC); + break; + + case ELEM_SHIFT_REGISTER: { + int i; + for(i = 0; i < l->d.shiftRegister.stages; i++) { + char str[MAX_NAME_LEN+10]; + sprintf(str, "%s%d", l->d.shiftRegister.name, i); + AppendIo(str, IO_TYPE_GENERAL); + } + break; + } + + case ELEM_LOOK_UP_TABLE: + AppendIo(l->d.lookUpTable.dest, IO_TYPE_GENERAL); + break; + + case ELEM_PIECEWISE_LINEAR: + AppendIo(l->d.piecewiseLinear.dest, IO_TYPE_GENERAL); + break; + + case ELEM_PLACEHOLDER: + case ELEM_COMMENT: + case ELEM_SHORT: + case ELEM_OPEN: + case ELEM_MASTER_RELAY: + case ELEM_ONE_SHOT_RISING: + case ELEM_ONE_SHOT_FALLING: + case ELEM_EQU: + case ELEM_NEQ: + case ELEM_GRT: + case ELEM_GEQ: + case ELEM_LES: + case ELEM_LEQ: + case ELEM_RES: + case ELEM_PERSIST: + break; + + default: + oops(); + } +} + +//----------------------------------------------------------------------------- +// Compare function to qsort() the I/O list. Group by type, then +// alphabetically within each section. +//----------------------------------------------------------------------------- +static int CompareIo(const void *av, const void *bv) +{ + PlcProgramSingleIo *a = (PlcProgramSingleIo *)av; + PlcProgramSingleIo *b = (PlcProgramSingleIo *)bv; + + if(a->type != b->type) { + return a->type - b->type; + } + + if(a->pin == NO_PIN_ASSIGNED && b->pin != NO_PIN_ASSIGNED) return 1; + if(b->pin == NO_PIN_ASSIGNED && a->pin != NO_PIN_ASSIGNED) return -1; + + return strcmp(a->name, b->name); +} + +//----------------------------------------------------------------------------- +// Wipe the I/O list and then re-extract it from the PLC program, taking +// care not to forget the pin assignments. Gets passed the selected item +// as an index into the list; modifies the list, so returns the new selected +// item as an index into the new list. +//----------------------------------------------------------------------------- +int GenerateIoList(int prevSel) +{ + int i, j; + + char selName[MAX_NAME_LEN]; + if(prevSel >= 0) { + strcpy(selName, Prog.io.assignment[prevSel].name); + } + + if(IoSeenPreviouslyCount > MAX_IO_SEEN_PREVIOUSLY/2) { + // flush it so there's lots of room, and we don't run out and + // forget important things + IoSeenPreviouslyCount = 0; + } + + // remember the pin assignments + for(i = 0; i < Prog.io.count; i++) { + AppendIoSeenPreviously(Prog.io.assignment[i].name, + Prog.io.assignment[i].type, Prog.io.assignment[i].pin); + } + // wipe the list + Prog.io.count = 0; + // extract the new list so that it must be up to date + for(i = 0; i < Prog.numRungs; i++) { + ExtractNamesFromCircuit(ELEM_SERIES_SUBCKT, Prog.rungs[i]); + } + + for(i = 0; i < Prog.io.count; i++) { + if(Prog.io.assignment[i].type == IO_TYPE_DIG_INPUT || + Prog.io.assignment[i].type == IO_TYPE_DIG_OUTPUT || + Prog.io.assignment[i].type == IO_TYPE_READ_ADC) + { + for(j = 0; j < IoSeenPreviouslyCount; j++) { + if(strcmp(Prog.io.assignment[i].name, + IoSeenPreviously[j].name)==0) + { + Prog.io.assignment[i].pin = IoSeenPreviously[j].pin; + break; + } + } + } + } + + qsort(Prog.io.assignment, Prog.io.count, sizeof(PlcProgramSingleIo), + CompareIo); + + if(prevSel >= 0) { + for(i = 0; i < Prog.io.count; i++) { + if(strcmp(Prog.io.assignment[i].name, selName)==0) + break; + } + if(i < Prog.io.count) + return i; + } + // no previous, or selected was deleted + return -1; +} + +//----------------------------------------------------------------------------- +// Load the I/O list from a file. Since we are just loading pin assignments, +// put it into IoSeenPreviously so that it will get used on the next +// extraction. +//----------------------------------------------------------------------------- +BOOL LoadIoListFromFile(FILE *f) +{ + char line[80]; + char name[MAX_NAME_LEN]; + int pin; + while(fgets(line, sizeof(line), f)) { + if(strcmp(line, "END\n")==0) { + return TRUE; + } + // Don't internationalize this! It's the file format, not UI. + if(sscanf(line, " %s at %d", name, &pin)==2) { + int type; + switch(name[0]) { + case 'X': type = IO_TYPE_DIG_INPUT; break; + case 'Y': type = IO_TYPE_DIG_OUTPUT; break; + case 'A': type = IO_TYPE_READ_ADC; break; + default: oops(); + } + AppendIoSeenPreviously(name, type, pin); + } + } + return FALSE; +} + +//----------------------------------------------------------------------------- +// Write the I/O list to a file. Since everything except the pin assignment +// can be extracted from the schematic, just write the Xs and Ys. +//----------------------------------------------------------------------------- +void SaveIoListToFile(FILE *f) +{ + int i; + for(i = 0; i < Prog.io.count; i++) { + if(Prog.io.assignment[i].type == IO_TYPE_DIG_INPUT || + Prog.io.assignment[i].type == IO_TYPE_DIG_OUTPUT || + Prog.io.assignment[i].type == IO_TYPE_READ_ADC) + { + // Don't internationalize this! It's the file format, not UI. + fprintf(f, " %s at %d\n", Prog.io.assignment[i].name, + Prog.io.assignment[i].pin); + } + } +} + +//----------------------------------------------------------------------------- +// Dialog proc for the popup that lets you set the value of an analog input for +// simulation. +//----------------------------------------------------------------------------- +static LRESULT CALLBACK AnalogSliderDialogProc(HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_CLOSE: + case WM_DESTROY: + AnalogSliderDone = TRUE; + AnalogSliderCancel = TRUE; + return 1; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } +} + +//----------------------------------------------------------------------------- +// A little toolbar-style window that pops up to allow the user to set the +// simulated value of an ADC pin. +//----------------------------------------------------------------------------- +void ShowAnalogSliderPopup(char *name) +{ + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + + wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | + CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)AnalogSliderDialogProc; + wc.hInstance = Instance; + wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; + wc.lpszClassName = "LDmicroAnalogSlider"; + wc.lpszMenuName = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + RegisterClassEx(&wc); + + POINT pt; + GetCursorPos(&pt); + + SWORD currentVal = GetAdcShadow(name); + + SWORD maxVal; + if(Prog.mcu) { + maxVal = Prog.mcu->adcMax; + } else { + maxVal = 1023; + } + if(maxVal == 0) { + Error(_("No ADC or ADC not supported for selected micro.")); + return; + } + + int left = pt.x - 10; + // try to put the slider directly under the cursor (though later we might + // realize that that would put the popup off the screen) + int top = pt.y - (15 + (73*currentVal)/maxVal); + + RECT r; + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + + if(top + 110 >= r.bottom) { + top = r.bottom - 110; + } + if(top < 0) top = 0; + + AnalogSliderMain = CreateWindowClient(0, "LDmicroAnalogSlider", "I/O Pin", + WS_VISIBLE | WS_POPUP | WS_DLGFRAME, + left, top, 30, 100, NULL, NULL, Instance, NULL); + + AnalogSliderTrackbar = CreateWindowEx(0, TRACKBAR_CLASS, "", WS_CHILD | + TBS_AUTOTICKS | TBS_VERT | TBS_TOOLTIPS | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, 0, 30, 100, AnalogSliderMain, NULL, Instance, NULL); + SendMessage(AnalogSliderTrackbar, TBM_SETRANGE, FALSE, + MAKELONG(0, maxVal)); + SendMessage(AnalogSliderTrackbar, TBM_SETTICFREQ, (maxVal + 1)/8, 0); + SendMessage(AnalogSliderTrackbar, TBM_SETPOS, TRUE, currentVal); + + EnableWindow(MainWindow, FALSE); + ShowWindow(AnalogSliderMain, TRUE); + SetFocus(AnalogSliderTrackbar); + + DWORD ret; + MSG msg; + AnalogSliderDone = FALSE; + AnalogSliderCancel = FALSE; + + SWORD orig = GetAdcShadow(name); + + while(!AnalogSliderDone && (ret = GetMessage(&msg, NULL, 0, 0))) { + SWORD v = (SWORD)SendMessage(AnalogSliderTrackbar, TBM_GETPOS, 0, 0); + + if(msg.message == WM_KEYDOWN) { + if(msg.wParam == VK_RETURN) { + AnalogSliderDone = TRUE; + break; + } else if(msg.wParam == VK_ESCAPE) { + AnalogSliderDone = TRUE; + AnalogSliderCancel = TRUE; + break; + } + } else if(msg.message == WM_LBUTTONUP) { + if(v != orig) { + AnalogSliderDone = TRUE; + } + } + SetAdcShadow(name, v); + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if(!AnalogSliderCancel) { + SWORD v = (SWORD)SendMessage(AnalogSliderTrackbar, TBM_GETPOS, 0, 0); + SetAdcShadow(name, v); + } + + EnableWindow(MainWindow, TRUE); + DestroyWindow(AnalogSliderMain); + ListView_RedrawItems(IoList, 0, Prog.io.count - 1); +} + +//----------------------------------------------------------------------------- +// Window proc for the contacts dialog box +//----------------------------------------------------------------------------- +static LRESULT CALLBACK IoDialogProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + switch (msg) { + 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; + } else if(h == PinList && HIWORD(wParam) == LBN_DBLCLK) { + DialogDone = TRUE; + } + break; + } + + case WM_CLOSE: + case WM_DESTROY: + DialogDone = TRUE; + DialogCancel = TRUE; + return 1; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Create our window class; nothing exciting. +//----------------------------------------------------------------------------- +static BOOL MakeWindowClass() +{ + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + + wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | + CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)IoDialogProc; + wc.hInstance = Instance; + wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; + wc.lpszClassName = "LDmicroIo"; + 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); + + return RegisterClassEx(&wc); +} + +static void MakeControls(void) +{ + HWND textLabel = CreateWindowEx(0, WC_STATIC, _("Assign:"), + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, + 6, 1, 80, 17, IoDialog, NULL, Instance, NULL); + NiceFont(textLabel); + + PinList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTBOX, "", + WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | WS_VSCROLL | + LBS_NOTIFY, 6, 18, 95, 320, IoDialog, NULL, Instance, NULL); + FixedFont(PinList); + + OkButton = CreateWindowEx(0, WC_BUTTON, _("OK"), + WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | BS_DEFPUSHBUTTON, + 6, 325, 95, 23, IoDialog, NULL, Instance, NULL); + NiceFont(OkButton); + + CancelButton = CreateWindowEx(0, WC_BUTTON, _("Cancel"), + WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE, + 6, 356, 95, 23, IoDialog, NULL, Instance, NULL); + NiceFont(CancelButton); +} + +void ShowIoDialog(int item) +{ + if(!Prog.mcu) { + MessageBox(MainWindow, + _("No microcontroller has been selected. You must select a " + "microcontroller before you can assign I/O pins.\r\n\r\n" + "Select a microcontroller under the Settings menu and try " + "again."), _("I/O Pin Assignment"), MB_OK | MB_ICONWARNING); + return; + } + + if(Prog.mcu->whichIsa == ISA_ANSIC) { + Error(_("Can't specify I/O assignment for ANSI C target; compile and " + "see comments in generated source code.")); + return; + } + + if(Prog.mcu->whichIsa == ISA_INTERPRETED) { + Error(_("Can't specify I/O assignment for interpretable target; see " + "comments in reference implementation of interpreter.")); + return; + } + + if(Prog.io.assignment[item].name[0] != 'X' && + Prog.io.assignment[item].name[0] != 'Y' && + Prog.io.assignment[item].name[0] != 'A') + { + Error(_("Can only assign pin number to input/output pins (Xname or " + "Yname or Aname).")); + return; + } + + if(Prog.io.assignment[item].name[0] == 'A' && Prog.mcu->adcCount == 0) { + Error(_("No ADC or ADC not supported for this micro.")); + return; + } + + if(strcmp(Prog.io.assignment[item].name+1, "new")==0) { + Error(_("Rename I/O from default name ('%s') before assigning " + "MCU pin."), Prog.io.assignment[item].name); + return; + } + + MakeWindowClass(); + + // We need the TOOLWINDOW style, or else the window will be forced to + // a minimum width greater than our current width. And without the + // APPWINDOW style, it becomes impossible to get the window back (by + // Alt+Tab or taskbar). + IoDialog = CreateWindowClient(WS_EX_TOOLWINDOW | WS_EX_APPWINDOW, + "LDmicroIo", _("I/O Pin"), + WS_OVERLAPPED | WS_SYSMENU, + 100, 100, 107, 387, NULL, NULL, Instance, NULL); + + MakeControls(); + + SendMessage(PinList, LB_ADDSTRING, 0, (LPARAM)_("(no pin)")); + int i; + for(i = 0; i < Prog.mcu->pinCount; i++) { + int j; + for(j = 0; j < Prog.io.count; j++) { + if(j == item) continue; + if(Prog.io.assignment[j].pin == Prog.mcu->pinInfo[i].pin) { + goto cant_use_this_io; + } + } + + if(UartFunctionUsed() && Prog.mcu && + ((Prog.mcu->pinInfo[i].pin == Prog.mcu->uartNeeds.rxPin) || + (Prog.mcu->pinInfo[i].pin == Prog.mcu->uartNeeds.txPin))) + { + goto cant_use_this_io; + } + + if(PwmFunctionUsed() && + Prog.mcu->pinInfo[i].pin == Prog.mcu->pwmNeedsPin) + { + goto cant_use_this_io; + } + + if(Prog.io.assignment[item].name[0] == 'A') { + for(j = 0; j < Prog.mcu->adcCount; j++) { + if(Prog.mcu->adcInfo[j].pin == Prog.mcu->pinInfo[i].pin) { + // okay; we know how to connect it up to the ADC + break; + } + } + if(j == Prog.mcu->adcCount) { + goto cant_use_this_io; + } + } + + char buf[40]; + if(Prog.mcu->pinCount <= 21) { + sprintf(buf, "%3d %c%c%d", Prog.mcu->pinInfo[i].pin, + Prog.mcu->portPrefix, Prog.mcu->pinInfo[i].port, + Prog.mcu->pinInfo[i].bit); + } else { + sprintf(buf, "%3d %c%c%d", Prog.mcu->pinInfo[i].pin, + Prog.mcu->portPrefix, Prog.mcu->pinInfo[i].port, + Prog.mcu->pinInfo[i].bit); + } + SendMessage(PinList, LB_ADDSTRING, 0, (LPARAM)buf); +cant_use_this_io:; + } + + EnableWindow(MainWindow, FALSE); + ShowWindow(IoDialog, TRUE); + SetFocus(PinList); + + MSG msg; + DWORD ret; + DialogDone = FALSE; + DialogCancel = FALSE; + while((ret = GetMessage(&msg, NULL, 0, 0)) && !DialogDone) { + if(msg.message == WM_KEYDOWN) { + if(msg.wParam == VK_RETURN) { + DialogDone = TRUE; + break; + } else if(msg.wParam == VK_ESCAPE) { + DialogDone = TRUE; + DialogCancel = TRUE; + break; + } + } + + if(IsDialogMessage(IoDialog, &msg)) continue; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if(!DialogCancel) { + int sel = SendMessage(PinList, LB_GETCURSEL, 0, 0); + char pin[16]; + SendMessage(PinList, LB_GETTEXT, (WPARAM)sel, (LPARAM)pin); + if(strcmp(pin, _("(no pin)"))==0) { + int i; + for(i = 0; i < IoSeenPreviouslyCount; i++) { + if(strcmp(IoSeenPreviously[i].name, + Prog.io.assignment[item].name)==0) + { + IoSeenPreviously[i].pin = NO_PIN_ASSIGNED; + } + } + Prog.io.assignment[item].pin = NO_PIN_ASSIGNED; + } else { + Prog.io.assignment[item].pin = atoi(pin); + // Only one name can be bound to each pin; make sure that there's + // not another entry for this pin in the IoSeenPreviously list, + // that might get used if the user creates a new pin with that + // name. + int i; + for(i = 0; i < IoSeenPreviouslyCount; i++) { + if(IoSeenPreviously[i].pin == atoi(pin)) { + IoSeenPreviously[i].pin = NO_PIN_ASSIGNED; + } + } + } + } + + EnableWindow(MainWindow, TRUE); + DestroyWindow(IoDialog); + return; +} + +//----------------------------------------------------------------------------- +// Called in response to a notify for the listview. Handles click, text-edit +// operations etc., but also gets called to find out what text to display +// where (LPSTR_TEXTCALLBACK); that way we don't have two parallel copies of +// the I/O list to keep in sync. +//----------------------------------------------------------------------------- +void IoListProc(NMHDR *h) +{ + switch(h->code) { + case LVN_GETDISPINFO: { + NMLVDISPINFO *i = (NMLVDISPINFO *)h; + int item = i->item.iItem; + switch(i->item.iSubItem) { + case LV_IO_PIN: + // Don't confuse people by displaying bogus pin assignments + // for the C target. + if(Prog.mcu && (Prog.mcu->whichIsa == ISA_ANSIC || + Prog.mcu->whichIsa == ISA_INTERPRETED) ) + { + strcpy(i->item.pszText, ""); + break; + } + + PinNumberForIo(i->item.pszText, + &(Prog.io.assignment[item])); + break; + + case LV_IO_TYPE: { + char *s = IoTypeToString(Prog.io.assignment[item].type); + strcpy(i->item.pszText, s); + break; + } + case LV_IO_NAME: + strcpy(i->item.pszText, Prog.io.assignment[item].name); + break; + + case LV_IO_PORT: { + // Don't confuse people by displaying bogus pin assignments + // for the C target. + if(Prog.mcu && Prog.mcu->whichIsa == ISA_ANSIC) { + strcpy(i->item.pszText, ""); + break; + } + + int type = Prog.io.assignment[item].type; + if(type != IO_TYPE_DIG_INPUT && type != IO_TYPE_DIG_OUTPUT + && type != IO_TYPE_READ_ADC) + { + strcpy(i->item.pszText, ""); + break; + } + + int pin = Prog.io.assignment[item].pin; + if(pin == NO_PIN_ASSIGNED || !Prog.mcu) { + strcpy(i->item.pszText, ""); + break; + } + + if(UartFunctionUsed() && Prog.mcu) { + if((Prog.mcu->uartNeeds.rxPin == pin) || + (Prog.mcu->uartNeeds.txPin == pin)) + { + strcpy(i->item.pszText, _("<UART needs!>")); + break; + } + } + + if(PwmFunctionUsed() && Prog.mcu) { + if(Prog.mcu->pwmNeedsPin == pin) { + strcpy(i->item.pszText, _("<PWM needs!>")); + break; + } + } + + int j; + for(j = 0; j < Prog.mcu->pinCount; j++) { + if(Prog.mcu->pinInfo[j].pin == pin) { + sprintf(i->item.pszText, "%c%c%d", + Prog.mcu->portPrefix, + Prog.mcu->pinInfo[j].port, + Prog.mcu->pinInfo[j].bit); + break; + } + } + if(j == Prog.mcu->pinCount) { + sprintf(i->item.pszText, _("<not an I/O!>")); + } + break; + } + + case LV_IO_STATE: { + if(InSimulationMode) { + char *name = Prog.io.assignment[item].name; + DescribeForIoList(name, i->item.pszText); + } else { + strcpy(i->item.pszText, ""); + } + break; + } + + } + break; + } + case LVN_ITEMACTIVATE: { + NMITEMACTIVATE *i = (NMITEMACTIVATE *)h; + if(InSimulationMode) { + char *name = Prog.io.assignment[i->iItem].name; + if(name[0] == 'X') { + SimulationToggleContact(name); + } else if(name[0] == 'A') { + ShowAnalogSliderPopup(name); + } + } else { + UndoRemember(); + ShowIoDialog(i->iItem); + ProgramChanged(); + InvalidateRect(MainWindow, NULL, FALSE); + } + break; + } + } +} |