Getting all serial numbers related to an assembly to display - reportbuilder3.0

First time asking a question here in SO. I am working with Report Builder, and I am having issues with getting all serial numbers for a particular assembly number in a manufacturing setting. Sometimes there is only a single serial number per assembly, sometimes there are multiple serial numbers in an assembly.
Admittedly, I'm not the most versed with report builder.
Here is the expression that I have created to try and solve the issue:
=Join(Code.RemoveDuplicates(LookupSet(1, 1, Fields!SerialNumber.Value,"JobHead")),", ")
with this code, I am able to get all the serial numbers for the Assemblies to display, but now they show on every page instead of listing the serial number for the specific assembly:
Example Image:
Showing that two assemblies are selected, 0 and 2:
Page for assembly 0 shows serial numbers for both assembly 0 and 2:
For this example, I have selected two Assemblies, numbers 0 and 2, you will notice two serial numbers listed for "ASM 0" (assembly 0). The true result should only display serial number "0003" whereas the "0001" should only display on the report page for Assembly 2.
I need help populating the correct serial number/s on their respected assembly reports.

Solution:
=iif(CountDistinct(fields!SerialNumber.Value)>1,Join(Code.RemoveDuplicates(LookupSet(1, 1, Fields!SerialNumber.Value,"JobHead")),", "),fields!SerialNumber.value)
Credit to: Milkah Gichaba

Related

Finding and patching an instruction in a DLL

I have a (C++) program where, in one of its dll's, the following is done:
if (m_Map.GetMaxValue() >= MAX_CLASSES) {
I have two binaries of this program (compiled with various versions of Visual Studio), one where MAX_CLASSES was #define'd to 50, and one where it was 75. These binaries were made from different branches of the code and the other functionality is different as well. What I need is a version of the binary where the MAX_CLASSES was defined as 50, except with the higher limit i.e. 75.
So a sane person would change the constant in the source code of the branch I need, rebuild and go home. But, building this software is complex because it's old, the dependencies and tooling are old, etc.; plus I have issues with building the installers, and data and so on. So, I thought, how about I just patch this binary so that this one constant is changed directly in the DLL. I have vague recollections of doing similar things in the 1990's for, eh, probably 'educational' purposes.
But times have changed and I barely remember doing it, let alone how I did things back then. I opened the DLL (one where the limit is set to 75, this is the binary I have at hand - I will have to re-do this as soon as I have the actual binary with the 50 limit, so the following references 75 i.e. 0x4b for illustrating the principle) in Ghidra and after some poking around, I found the following:
18005160e 3c 4b CMP AL,0x4b
180051610 0f 82 19 JC LAB_18005172f
01 00 00
Which in the decompiler window I could link back to
if (bVar3 < 0x4b)
and some operations after that that I can map to the source code of the function I have.
Now my questions are:
how do I interpret the values above (the Ghidra output) wrt to the binary layout of the dll? When I hover over the first column value ('18005160e') in Ghidra, I get values for 'imagebase offset', 'memory block offset', 'function offset' and 'byte source offset'. Is this 'byte source offset' the physical address from the start of the dll where these instructions start? The actual value in this hover balloon is 50a0eh - is that Ghidra's notation for 0x50a0e ? I.e. does the trailing 'h' denote 'hex'?
I then tried to open the dll in a regular hex editor ('Hex Editor Neo' which I like to use to view/edit binary data files), and went to offset 0x50a0e, and looked for the values '3c 4b' around there which I didn't find. I searched for this byte sequence in the whole file, and found 7 occurrences, none of which are around 0x50a0e, leading me to think I'm misinterpreting Ghidra's 'byte source offset' here.
how do I make a 'patcher' for this? I would think what I need is a program that only does
FILE* fh = fopen('mydll.dll);
fseek(fh, 0x[magic constant]);
fwrite(fh, 0x4b);
fclose(fh);
where '0x[magic constant]' is hopefully just the value I got from Ghidra in 'byte source offset'? Or is there anything else I need to consider here? Is there any software tool that can generate a patcher program?
Thanks.
18005160e is a VA, a Virtual Address.
It is the sum of a Base Address (most likely 180000000) and an RVA, a Relative Virtual Address.
Find the Base Address of the DLL with any PE inspecting tool (e.g. CFF Explorer) or Ghidra itself.
Subtract the base address from 18005160e to the RVA. Let's say the result is 5160e.
Now you need to find which section this RVA lies in. Again use an PE inspecting tool to find the list of the sections and their RVA/Virtual start and RVA/Virtual size.
Say the RVA lies in the .text section with start at the RVA 1000.
Subtract this start RVA from the result above: 5160e - 1000 = 4160e.
This is the offset of the instruction in the .text section.
To find the offset in the file, just add the raw/offset start of the section (again you can find this with a PE inspecting tool).
Say the .text section starts at the offset 400, then 4160e + 400 = 41a0e is the offset corresponding to the VA 18005160e.
This is all PE 101.

what is meaning of pgd_bad, pmd_bad, pud_bad, while converting kernel addressess?

Can somebody please explain below macros in kernel page tables?
#define pgd_bad(pgd) (!(pgd_val(pgd) & 2))
#define pmd_bad(pmd) (!(pmd_val(pmd) & 2))
#define pud_bad(pud) (!(pud_val(pud) & 2))
As originally defined in the now rather out of date (but excellent) Understanding the Linux Virtual Memory Manager _bad() macros determine whether a specified page table entry is not in a suitable state for modification.
However it turns out the macros are slightly nebulous across architectures, and might better be described in arm64 as determining whether an entry does not contain a reference to a page containing the table for the next level page table - see this commit for some details.
Expanding on #Notlikethat's answer, the macros do refer to the 'table' bit, which in turn (at least in linux kernel use, there might be more detailed architecture-specific details at play) determines whether the entry's physical address refers to a huge page (64KiB - see the arm64 memory layout doc) or not.
If we look at pte_huge() which determines whether a page entry refers to a huge page or not we see:
#define pte_huge(pte) (!(pte_val(pte) & PTE_TABLE_BIT))
This indicates that if the bit is set the page size is 4KiB, if it's cleared it's 64KiB and therefore huge.
This leads to the conclusion that, in arm64, the pXX_bad() macros return true if huge pages are used.
However, the definitions you give are actually not used if huge tables are enabled :)
Looking again at the memory layout doc referenced above, it turns out that the huge page table layout uses only 2 levels. The way linux deals with architectures which have less than 4 page table levels is to 'fold in' non-existent levels into existing tables, and let the compiler remove all of the unnecessary code.
And if we look at arch/arm64/include/asm/pgtable.h above the pgd_bad() definition (on line 445 at the time of writing), we see:
#if CONFIG_PGTABLE_LEVELS > 3
And above the pud_bad() definition (on line 392 at the time of writing) we see:
#if CONFIG_PGTABLE_LEVELS > 2
So in fact since CONFIG_PGTABLE_LEVELS == 2 in the huge table case, different definitions are used.
In arch/arm64/include/asm/pgtable-types.h we see (at line 89 at the time of writing):
#if CONFIG_PGTABLE_LEVELS == 2
#include <asm-generic/pgtable-nopmd.h>
#elif CONFIG_PGTABLE_LEVELS == 3
#include <asm-generic/pgtable-nopud.h>
#endif
So in fact definitions from include/asm-generic/pgtable-nopmd.h are used, which itself imports include/asm-generic/pgtable-nopud.h, giving us:
static inline int pgd_bad(pgd_t pgd) { return 0; }
static inline int pud_bad(pud_t pud) { return 0; }
And we already had:
#define pmd_bad(pmd) (!(pmd_val(pmd) & 2))
Which means that any huge page PMD entry which has pmd_bad() called on it will return true. However, if you look at the commit I mentioned above, you'll see that prior to the commit, a _bad() returning true would result in code handling the 'section map' case, where presumably the PMD contains different metadata (I don't want to dive too deep here :) and separate code is used, now that's handled via pmd_sect() and we don't care about what pmd_bad() says, if the entry is a section map.
Looking at arch/arm64/mm/mmu.c, pmd_set_huge() (line 828 at the time of writing), it seems like huge table PMDs are set as section maps meaning that we don't need to care about pmd_bad() (I may be mistaken here, I've not looked deep or gone through with a debugger, but it seems this way.)
So it seems overall the _bad() case now means something different - it just indicates that a bug has resulted in some code that's meant to be handling a non-section map/huge page table entry is handling a huge section map page table entry, which clearly needs to be indicated.
NOTE: Since I created an account just to reply here, I don't have enough reputation to give more links :) a kind person with more rep might want to add links where they make sense to, e.g. the 'at line XX at the time of writing' entries.)
In the ARMv8 64-bit page table descriptor format, for a valid (i.e. bit 0 set) level 0, 1, or 2 entry, bit 1 discriminates between table and block (hugepage) entries. Thus these macros will return false if the given entry has bit 1 set, indicating the expected table entry, or true if it is clear indicating a block or invalid entry. The p*d_val() accessors are simply wrappers for optionally enforcing type-safety.

VB6 MSComm, ports above 127 return 8002

I have a simple function that checks if we have open ports on the system, I would test ports from 1 to 256. For some odd reason when I have device at port over 127 system returns error 8002. This is very odd because when I use a different C++ application to check connection device is found and is available for reading.
This issue is related to the MSComm32.OCX, which has a limit on how many ports are available. I need to increase this limit to 256. I found a list of instruction below, but I wasn't able to find "3D 10 00" in the MSComm32.OCX file, this was on Windows 8 PC. However, on Windows XP MSComm32.OCX did contain "3D 10 00", i quickly found the string and added a new byte "FF" and deleted byte "10" using http://mh-nexus.de/en/hxd/ and saved it as a new file.
First you copy the file MSCOMM32.OCX to a safe place.
1. Obtain a HEX editor.
2. Open de file MSCOMM32.OCX
3. Find the string "3D 10 00"
4. There should be only one. This string is unique.
5. Change the string to "3D FF 00"
6. Save the file.
I don't know if this will help in your case, but you will be unable to edit the original ocx file using this procedure. You can only edit the file after it has been registered. The original is the "cookie cutter" from which all registered files are descended and it has a completely different structure. The registered file will have the "3D 10 00" sequence in it and can be modified. It would be nice if the original could be modified since all new instances would then have the modified upper port limit already in them, but Microsoft made sure that won't work.

Arduino serial sometimes gives random values

I am using a MMA7361 accelerometer from sparkfun that is connected to my arduino uno and it is in turn connected to my pc.
I am simply reading the values from each axis(x,y,z) and sending them straight through the serial port to my pc with a series of Serial.print and Serial.write. From there I have set up a program to read and display the info with myPort.readString();
Now it works fine 80% of the time and it gives the right results and all, but sometimes I get some random value sent through the serial port and it messes up the receiving program making me unable to use the signal properly.
I am pretty sure its not the sensor itself sending the disturbing signal because I have tried to save 10 different readings and then sending an average to minimize the effect with no luck. The receiving pc still got the weird value spikes around 0-200 (from what I saw as output).
I tried with pulling out the cable that connects from the sensor to the analog in port and weirdly it gave out some random value instead of the expected 0, I'm not sure but for me it seems like that has something to do about my problem.
I have read about some kind of pull down resistor but that only works for buttons, right?
I just got my arduino and I'm trying to learn how to use sensors and what you can do with them and what can go wrong so I'd appreciate if someone could help me with this :)
Heres an example of the random value messing up the output:
252:236:218
251:202:215
2 <-- this is where it begins
59:231:245
28
4:144:142 <-- messing up the order of the values
251:19
2:187
246:235
:244
240:190:
238
250:202:2
32
248:243:224
245:227:240
251:228:244
253:223:241
If you want I got the code for sending and recieving too:
Serial.print(analogRead(xpin));
Serial.write(":");
Serial.print(analogRead(ypin));
Serial.write(":");
Serial.println(analogRead(zpin));
I'd really like the sending to be just one line of code but I haven't been able to join all numbers and strings to a one line string on the arduino.
Recieving:
if ( myPort.available() > 0) {
result = myPort.readString();
println(result);
}
Looking at your output, it seems that the values are all received, but somehow a CR and/or LF character is added to the output. And that comes from the println statement:
if ( myPort.available() > 0) {
result = myPort.readString();
println(result);
}
What happens is that the receiving end gets some characters (not necessarily all), it prints them, adding a linefeed character then exits the function.
Then it enters the if statement again and prints the available characters in the buffer. And so it goes.
If you wish to ensure a consistent output you have to either
1. build a packet of the data or
2. Count the received bytes and print them when all are received.
As to 1. it would be my preferred method, add a start- and end-character to the data. The receiving end will then know that all data between the start- and end-character is the data to be printed.
I seem to have fixed this by using readChar and checking if the current character inputted is the delimiter. It is a bit slower but it works.

WIA - determining the page count

I am using WIA2.0 on VB6.
I could do scanning without anyissues..
But, the problem is i could not figure out the number of pages scanned when it's ADF.
I could see something like this in msdn.
WIA_DPS_ENDORSER_STRING with a token as
$PAGE_COUNT$ The number of pages transferred.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms630195(v=vs.85).aspx
But, i don't know how to access this in VB6.
Any help would be appriciated.
Thanks.
-Dinakaran.AS
As far as I can tell this count is probably strictly local to the scanner itself when it has an endorser printer. It may even be a "hardware" counter much like photocopier counters. It probably can only be reset using a physical key or administrative password at the scanner to unlock and reset it. Looks as if it is meant for auditing purposes.
WIA_DPS_ENDORSER_CHARACTERS (ScannerDeviceEndorserCharacters)
Contains all the valid characters that an application can use to
create valid endorser strings. An endorser is a printer installed on a
scanner that imprints a text message on every page scanned. The
minidriver should validate the setting of the WIA_DPS_ENDORSER_STRING
property against the valid character set in this property. The
minidriver creates and maintains this property.
WIA_DPS_ENDORSER_STRING (ScannerDeviceEndorserString)
Contains a string that is to be endorsed (in other words, printed) on
each page that the minidriver scans. An application sets this property
using the valid character set that is reported in the
WIA_DPS_ENDORSER_CHARACTERS property. The minidriver should endorse
documents only if a string is set in this property. An empty string
means that the endorser functionality is disabled.
Then we have:
WIA_IPS_PAGES (ScannerPicturePages)
Note: This property is supported only by Windows Vista and later.
Contains the current number of pages to be acquired from an automatic
document feeder. The minidriver creates and maintains this property.
Type: VT_I4; Access: Read/Write; Valid values: WIA_PROP_RANGE This is
zero through the maximum number of pages that the scanner can scan.
The value is ALL_PAGES (= 0) if the scanner can scan continuously.
An application reads this property to determine the document feeder's
page capacity. The application also sets this property to the number
of pages it is going to scan.

Resources